home *** CD-ROM | disk | FTP | other *** search
/ Multimedia Jumpstart / Multimedia Microsoft Jumpstart Version 1.1a (Microsoft).BIN / develpmt / drivers / mscdex / hitachi / cd.asm next >
Encoding:
Assembly Source File  |  1990-10-15  |  95.4 KB  |  2,955 lines

  1. ; ***************************************************************************
  2. ; *                                                                         *
  3. ; * Hitachi CDR-3600/1600S C D - R O M Device Driver                        *
  4. ; * Copyright reserved by Hitachi, Ltd.                                     *
  5. ; *                                                                         *
  6. ; * C D - R O M Device Driver Hardware Dependent Interface.                 *
  7. ; *                                                                         *
  8. ; * This file defines the hardware dependent interface to the valid CD-ROM  *
  9. ; * device driver commands, and helper functions in the file MSCDEX.ASM.    *
  10. ; * The implementation of a CD-ROM device driver entails replacing these    *
  11. ; * fucntions with suitable equivalents which adhere to the entry and exit  *
  12. ; * conditions defined.                                                     *
  13. ; *                                                                         *
  14. ; * History:                                                                *
  15. ; *                                                                         *
  16. ; * Created  (v1.02)                                                        *
  17. ; *     Oct. 07,1985     -by- H. ONO                                        *
  18. ; * Modified (v2.10)                                                        *
  19. ; *     1989-8-03        -by- T.ENOKI                                       *
  20. ; * Modified (v2.20)                                                        *
  21. ; *     Fri Jun 22 1990  -by- Michael Edwards                               *
  22. ; *                                                                         *
  23. ; *     Extensive code clean-up, seperated device dependent                 *
  24. ; *     code into this module, device independent into CD.ASM               *
  25. ; *                                                                         *
  26. ; *     Fixed bug in STOP AUDIO where wasn't re-setting the                 *
  27. ; *     paused bit correctly, and where was always returning                *
  28. ; *     through busy_good which says the drive is busy with                 *
  29. ; *     an audio play request.                                              *
  30. ; *                                                                         *
  31. ; *     Changed AUDIO command to return busy bit set if successful,         *
  32. ; *     and fixed bu in conversion of the passed starting sector            *
  33. ; *     number to redbook format.                                           *
  34. ; *                                                                         *
  35. ; *     Changed IOCTL OUTPUT's audio_channel_ctrl subfunction               *
  36. ; *     to detect assigning both input channels to one output               *
  37. ; *     channel, and suppressing the other.                                 *
  38. ; *                                                                         *
  39. ; *     Changed IOCTL INPUT's get UPC code to return sector not found error *
  40. ; *     (in addition to zero CONTROL/ADR and UPC bytes) when the UPC code is*
  41. ; *     not present on the disc.                                            *
  42. ; *                                                                         *
  43. ; *     Moved initializing timing variables from CDREAD to cdrom_init().    *
  44. ; *     Changed timing checks done after initialization to use the system's *
  45. ; *     18Hz clock long interger value (at 004:006c) instead of installing  *
  46. ; *     the timer interrupt routine.                                        *
  47. ; *                                                                         *
  48. ; * Modified (v2.20) -by- JohnYG 8/22/90                                    *
  49. ; *     v2.2b                                                               *
  50. ; *     Rewrote IOCTL Input cdrom_upc_code similar to Qchannel Info.        *
  51. ; *     Rewrote IOCTL Input cdrom_volume_size to use information from       *
  52. ; *     cdrom_audio_diskinfo rather than the undocumented call to hardware  *
  53. ; *     through CDREAD UCOM.                                                *
  54. ; *     v2.2c                                                               *
  55. ; *     Changed timeout values.  Fixed VolumeSize bug introduced in v2.2b   *
  56. ; *     v2.2d                                                               *
  57. ; *     Force the power save during play.  The default is not being set     *
  58. ; *     for the AMDEK, for some reason.                                     *
  59. ; *                                                                         *
  60. ; * Modified (v2.20) -by- JohnYG 10/1/90                                    *
  61. ; *     Final Release 10/1/90                                               *
  62. ; *                                                                         *
  63. ; ***************************************************************************
  64.  
  65.  
  66. CNT3            equ     8000            ;scan TOC timeout for read Q-channel
  67. RETRY_COUNT     equ     5
  68. SCAN_COUNT      equ     150
  69. UPC_COUNT       equ     150*2*RETRY_COUNT
  70.  
  71.         include cd.inc
  72.         include mscdex.inc
  73.         include macros.mac
  74.  
  75.         public  cdrom_read
  76.         public  cdrom_prefetch
  77.         public  cdrom_seek
  78.         public  cdrom_play_audio
  79.         public  cdrom_stop_audio
  80.         public  cdrom_location_head
  81.         public  cdrom_audio_channel_info
  82.         public  cdrom_read_drive_bytes
  83.         public  cdrom_device_status
  84.         public  cdrom_volume_size
  85.         public  cdrom_media_changed
  86.         public  cdrom_audio_diskinfo
  87.         public  cdrom_audio_trackinfo
  88.         public  cdrom_audio_Qchannel
  89.         public  cdrom_audio_Subchannel
  90.         public  cdrom_upc_code
  91.         public  cdrom_audio_status_info
  92.         public  cdrom_eject
  93.         public  cdrom_lock_door
  94.         public  cdrom_reset_drive
  95.         public  cdrom_audio_channel_ctrl
  96.         public  cdrom_write_drive_ctrl
  97.         public  cdrom_close_tray
  98.         public  cdrom_input_flush
  99.         public  cdrom_device_open
  100.         public  cdrom_device_close
  101.         public  cdrom_current_loc
  102.         public  cdrom_drive_status
  103.         public  cdrom_audio_check
  104.         public  cdrom_init
  105.  
  106.         extrn   BUF             : BYTE
  107.         extrn   CPU_MODE        : BYTE
  108.         extrn   CLOCK_MODE      : BYTE
  109.         extrn   CURRENT_IF_MODE : BYTE
  110.         extrn   STA_CODE        : BYTE
  111.         extrn   TWICE           : BYTE
  112.         extrn   IF_FLAG         : BYTE
  113.         extrn   CLOCK_COUNT     : BYTE
  114.         extrn   ERRCNT          : BYTE
  115.         extrn   CURRENT_IF      : WORD
  116.  
  117.         extrn   INSB_LOOP       : FAR
  118.         extrn   CDREAD          : FAR
  119.         extrn   _INSB_LOOP_ENT  : FAR
  120.         extrn   _STATUS_COMMAND : FAR
  121.  
  122.         extrn   bcd2red         : near
  123.         extrn   red2hsg         : near
  124.         extrn   hsg2red         : near
  125.         extrn   bcd2bin         : near
  126.         extrn   very_end        : near
  127.  
  128.         extrn   DeviceHeader    : word
  129.         extrn   units           : byte
  130.                       
  131. _TEXT   segment byte public 'CODE'
  132.         assume  cs:_TEXT
  133.  
  134.  
  135. disc_changed    db      8 dup(0)
  136. play_para       db      6 dup(0)        ;start/end play play time for device
  137. audio_vol       db      0               ;channel switching for drive 0
  138.                 db      0               ;volume for drive 1
  139.                 db      0               ;       "         2
  140.                 db      0               ;       "         3
  141.                 db      0               ;       "         4
  142.                 db      0               ;       "         5
  143.                 db      0               ;       "         6
  144.                 db      0               ;       "         7
  145.  
  146. audio_ch_work   label   byte
  147. left_ich        db      0               ;input ch. for output ch.0(left)
  148. left_vol        db      0ffh            ;volume for ch. 0(00h or other)
  149. right_ich       db      1               ;input ch. for output ch.1(right)
  150. right_vol       db      0ffh            ;volume for ch 1
  151. left2_ich       db      2               ;input ch. for output ch.2(left)
  152. left2_vol       db      0               ;volume for ch 2
  153. right2_ich      db      3               ;input ch. for output ch.3(right)
  154. right2_vol      db      0               ;volume for ch 3
  155. audio_ch_work_size = $-audio_ch_work
  156.  
  157. scans           dw      0               ;retry scanning
  158. i1              db      ?               ;retry counter for audio_diskinfo
  159. i2              dw      ?               ;"
  160. last_point      db      ?               ;last Q-channel point
  161. ok              db      ?               ;flag for audio_diskinfo
  162. vol_cnt         label   word            ; "    "     "    for vol-size
  163. loc_cnt         dw      0               ; "    "     "    for loc of head
  164. pwr_save        db      9               ; 0 - release  other - set power save
  165.  
  166. qbuf            db      size _QchanInfo dup(0)          ;subcode-Q work
  167. toc_drive       db      0ffh            ;which drive toc_table is for
  168. toc_table       label   byte
  169.                 db      size _QchanInfo dup(0)          ;POINT=A0,1st TNO
  170.                 db      size _QchanInfo dup(0)          ;POINT=A1,last TNO
  171.                 db      size _QchanInfo dup(0)          ;POINT=A2,lead-out
  172.                 db      99 dup (size _QchanInfo dup(0)) ;POINT=A0,1st TNO
  173. a_flag          db      ?               ;0/1 = audio_disk/trackinfo
  174. app_xfer_buffer dd      0               ;temp save for app's xfer buffer
  175.  
  176. ;============================================================
  177. ;
  178. ; READ LONG command
  179. ;
  180. ; Issue a read command to the drive.
  181. ;
  182. ; Entry:
  183. ;       dl:ax - redbook address for read
  184. ;       cx    - number of sectors to read
  185. ;       es:bx - transfer address for data
  186. ;       dh    - drive number (0 based)
  187. ;       di    - read mode (0 = cooked, 1 = raw) 
  188. ;
  189. ; Exit:
  190. ;       carry set   - error occurred, ax contains status word
  191. ;       carry clear - read was successful
  192. ;       trashes si
  193. ;
  194. ;============================================================
  195. cdrom_read proc near
  196.  
  197.         mov     si,cx                   ;si = num sectors to read
  198.         xchg    dl,dh                   ;dl = drive num
  199.         mov     ch,dh                   ;ch = minute
  200.         mov     cl,ah                   ;cl = second
  201.         mov     dh,al                   ;dh = frame
  202.         mov     ah,READ_COOKED
  203.         or      di,di                   ;used cooked mode?
  204.         je      @f                      ;  yes
  205.         mov     ah,READ_RAW             ;  no, read raw (2352 byte mode)
  206. @@:     mov     di,si
  207. ;
  208. ;      ah - READ RAW/COOKED
  209. ;   es:bx - transfer address
  210. ;ch,cl,dh - minute,second,frame
  211. ;      di - num frames
  212. ;
  213.         call    CDREAD                  ;Perform the read operation
  214.         jc      @f                      ;was there a read error?
  215.         ret                             ;  no
  216. @@:                                     ;  yes, get an error code to return
  217.         cmp     ah,08h                  ;Seek error ??
  218.         jne     @f                      ;  no, probably not
  219.         mov     ah,SEEK_CMD
  220.         call    CDREAD                  ;was it a sector not found error?
  221.         mov     cx,drverr_sector_not_found
  222.         jnc     read_failed             ;  yes
  223.  
  224.         mov     cx,drverr_seek_error
  225.         cmp     ah,08h                  ;Seek error ??
  226.         je      read_failed             ;  yes
  227. @@:
  228.         mov     cx,drverr_drive_not_ready
  229.         test    ah,14h                  ;Drive not ready or Time out ??
  230.         jnz     read_failed             ;  yes
  231.  
  232.         mov     cx,drverr_data_error
  233.         cmp     ah,80h                  ;Data error ??
  234.         je      read_failed             ; yes
  235.  
  236.         mov     cx,drverr_read_fault    ;must be a read fault
  237.  
  238. read_failed:
  239.         mov     ax,cx                   ;ax = error code
  240.         or      ax,(ERRBIT + DONEBIT)
  241.         stc
  242.         ret
  243.  
  244. cdrom_read endp
  245.  
  246.  
  247. ;============================================================
  248. ;
  249. ; PREFETCH command
  250. ;
  251. ; Asynchronously read sectors into internal drive or driver controlled
  252. ; buffers.
  253. ;
  254. ; The cheap way to implement the prefetch command is with a seek since
  255. ; prefetching is considered advisory.  If a drive, or the driver software,
  256. ; implement a "read-ahead" buffer, this entry point would initiate filling
  257. ; the buffer, in anticipation of a subsequent READ LONG command from the
  258. ; same location.
  259. ;
  260. ; Entry:
  261. ;       dl:ax - redbook address for read
  262. ;          cx - number of sectors to read
  263. ;       es:bx - transfer address for data
  264. ;          dh - drive number (0 based)
  265. ;          di - read mode (0 = cooked, 1 = raw) 
  266. ;
  267. ; Exit:
  268. ;       carry set   - error occurred, ax contains status word
  269. ;       carry clear - read was successful
  270. ;
  271. ;============================================================
  272. cdrom_prefetch:
  273.  
  274. ; fall through to the seek command.
  275. ;
  276.  
  277. ;============================================================
  278. ;
  279. ; SEEK command
  280. ;
  281. ; Issue a seek command to the drive.  This should cause the drive
  282. ; head to begin 'micro-seeking' at the indicated location in anticipation
  283. ; of receiving a command to read from there.  If the drive has read-ahead
  284. ; buffers the action should actually cause a read operation to occur, and
  285. ; not really 'micro-seek' unless the buffer fills before subsequent read 
  286. ; operations begin emptying it. 
  287. ;
  288. ; Entry:
  289. ;       dl:ax - redbook address for read
  290. ;          dh - drive number (0 based)
  291. ;
  292. ; Exit:
  293. ;       carry set   - error occurred, ax contains status word
  294. ;       carry clear - read was successful
  295. ;       trashes cx
  296. ;
  297. ;============================================================
  298. cdrom_seek proc near
  299.  
  300.         xchg    dl,dh                   ;dl = drive num
  301.         mov     ch,dh                   ;redbook minute
  302.         mov     cl,ah                   ;redbook second
  303.         mov     dh,al                   ;redbook frame
  304.         mov     ah,SEEK_CMD             ;seek without wait
  305.         call    CDREAD                  ;Perform the seek operation
  306.         jc      @f                      ;was there an error?
  307.         ret                             ;  no
  308. @@:
  309.         test    ah,0Ah                  ;  yes, was it a seek error?
  310.         mov     ax,(ERRBIT + DONEBIT + drverr_seek_error)
  311.         jnz     @f                      ; yes
  312.         mov     ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
  313. @@:     ret
  314.  
  315. cdrom_seek endp
  316.  
  317.  
  318. ;============================================================
  319. ;
  320. ; PLAY command
  321. ;
  322. ; Issue a play audio command to the drive.
  323. ;
  324. ; Entry:
  325. ;       dx:ax - audio ending HSG logical sector number
  326. ;       cx:di - audio start  HSG logical sector number
  327. ;          bx - drive num (0 based)
  328. ;
  329. ; Exit:
  330. ;       carry set   - error occurred, ax contains status word
  331. ;       carry clear - play was successful
  332. ;       trashes si,di
  333. ;
  334. ;============================================================
  335. cdrom_play_audio proc near
  336.  
  337. ; convert locations to redbook and put in drive buffer
  338. ;
  339.         lea     si,cs:play_para         ;parameter block for drive
  340.         call    hsg2red                 ;convert ending location
  341.         mov     cs:[si+3],dl
  342.         xchg    al,ah
  343.         mov     cs:[si+4],ax
  344.         mov     ax,di
  345.         mov     dx,cx
  346.         call    hsg2red                 ;convert starting location
  347.         mov     cs:[si],dl
  348.         xchg    al,ah
  349.         mov     cs:[si+1],ax
  350.  
  351.         mov     dx,bx                   ;get drive num
  352.  
  353. ; We need to force the power save off, the Amdek's are not doing this
  354. ; correctly
  355. ;
  356. ;       cmp     cs:pwr_save,0           ;drive turns off even when currently..
  357. ;       je      @f                      ;..playing audio!!!
  358.  
  359.         mov     ax,(SET_POWER_SAVE shl 8)
  360.         call    CDREAD
  361. @@:
  362.         mov     ax,cs
  363.         push    es
  364.         mov     es,ax
  365.         mov     al,cs:audio_vol[bx]     ;channel output (both, l, r or mute)
  366.         mov     di,bx                   ;preserve drive num
  367.         mov     bx,si                   ;es:bx -> drive's play parameters 
  368.         mov     ah,AUDIO_L_R_CMD
  369.         xor     cx,cx
  370.         call    CDREAD                  ;play that audio
  371.         mov     bx,di                   ;restore drive num
  372.         pop     es
  373.         jc      play_error              ;was the command successful?
  374.         mov     cs:loc_cnt,800          ;  yes, clear up and return success..
  375.  
  376. play_check:                             ;  ..if the play takes that is
  377.         call    cdrom_drive_status
  378.         jz      play_drive_not_ready
  379.         jc      @f
  380.         and     al,1ch
  381.         cmp     al,04h
  382.         je      play_done
  383. @@:     dec     cs:loc_cnt
  384.         jnz     play_check
  385.         mov     ah,PAUSE_CMD            ;the play command didn't take..
  386.         call    CDREAD                  ;..so perform a stop play..
  387.         jmp     short play_general_fail ;..and fail
  388.  
  389. play_done:
  390. ;
  391. ; play request was successful, return carry clear, di = drive number
  392. ;
  393.         ret
  394.  
  395. play_error:
  396.         test    ah,14h                  ;time out or drive not ready error?
  397.         jnz     play_drive_not_ready    ;
  398.         test    ah,08h                  ;was it a seek error ?
  399.         jnz     play_seek_error         ;  yes
  400.         jmp     short play_general_fail ;  no
  401.  
  402. play_drive_not_ready:
  403. ;
  404. ;also an entry point from RESUME AUDIO
  405. ;
  406.         mov     ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
  407.         jmp     short play_error_exit
  408.  
  409. play_general_fail:
  410. ;
  411. ; this is also an entry point from RESUME AUDIO
  412. ;
  413.         mov     ax,(ERRBIT + DONEBIT + drverr_general_failure)
  414.         jmp     short play_error_exit
  415.  
  416. play_seek_error:
  417.         mov     ax,(ERRBIT + DONEBIT + drverr_seek_error)
  418.  
  419. play_error_exit:
  420.         stc
  421.         ret
  422.  
  423. cdrom_play_audio endp
  424.  
  425.  
  426. ;============================================================
  427. ;
  428. ; STOP PLAY command
  429. ;
  430. ; Tell the drive not to play audio anymore.
  431. ; Entry:
  432. ;       bx - drive num (0 based)
  433. ;
  434. ; Exit:
  435. ;       carry set   - error occurred, ax contains status word
  436. ;       carry clear - stop/pause was successful
  437. ;
  438. ;============================================================
  439. cdrom_stop_audio proc near
  440.  
  441.         mov     al,cs:pwr_save          ;now that we're not playing audio..
  442.         or      al,al
  443.         je      @f
  444.         mov     ah,SET_POWER_SAVE       ;..restore the power save feature
  445.         mov     dx,bx
  446.         call    CDREAD
  447. @@:
  448.         mov     ah,PAUSE_CMD
  449.         call    CDREAD                  ;perform the stop play
  450.         mov     cs:loc_cnt,800
  451.         jnc     @f                      ;error occurred?
  452.         mov     ax,(ERRBIT + DONEBIT + drverr_general_failure)
  453.         ret                             ;  yes
  454. @@:                                     ;  no, but make sure the command took
  455.         call    cdrom_drive_status
  456.         jc      @f
  457.         test    al,40h                  ;door open?
  458.         jnz     @f
  459.         call    status_mode_check
  460.         jc      @f
  461.         cmp     al,04h                  ;still playing?
  462.         jne     @f                      ;  no
  463.         dec     cs:loc_cnt              ;  yes
  464.         jnz     @b
  465. @@:
  466.         clc
  467.         ret
  468.  
  469. cdrom_stop_audio endp
  470.  
  471.  
  472. ;============================================================
  473. ;
  474. ; RESUME PLAY command
  475. ;
  476. ;============================================================
  477. ;
  478. ; this command is handled in the device independend code (MSCDEX.ASM).
  479. ;
  480.  
  481.  
  482. ;============================================================
  483. ;
  484. ; IOCTL INPUT commands
  485. ;
  486. ;============================================================
  487.  
  488.  
  489. ;----------------------------------------------------------------------
  490. ;
  491. ; IOCTL INPUT sub-function #1
  492. ;
  493. ; Return the HSG address of the current head location.
  494. ;
  495. ; Entry:
  496. ;       bx - drive number to check head location
  497. ;
  498. ; Exit:
  499. ;       carry set   - an error occurred, ax contains the status word
  500. ;       carry clear - dx:ax = HSG logical sector address of the drive head
  501. ;
  502. ;----------------------------------------------------------------------
  503. cdrom_location_head proc near
  504.         
  505.         xchg    bx,di
  506.         call    cdrom_current_loc
  507.         jc      @f
  508.         test    ah,14h
  509.         mov     ax,(ERRBIT + DONEBIT + drverr_general_failure)
  510.         jz      @f                      ; is it really drive not ready?
  511.         mov     ax,(ERRBIT + DONEBIT + drverr_drive_not_ready) ; yep
  512.         stc
  513. @@:     xchg    bx,di
  514.         ret
  515.  
  516. cdrom_location_head endp
  517.  
  518.  
  519. ;----------------------------------------------------------------------
  520. ;
  521. ; IOCTL INPUT sub-function #4
  522. ;
  523. ; Report current audio channel control settings.  This will be the default
  524. ; arrangement of 1:1 input to output at full volume, otherwise it's whatever 
  525. ; was last set by the Audio Channnel Control IOCTL Output subfunction #3.
  526. ;
  527. ; Hitachi volume settings are limited to ON or OFF, so the convention of
  528. ; FFh for ON, and 00h for OFF is used.
  529. ; Hitachi forces channel settings for 3 and 4 to default values.
  530. ;
  531. ; Entry:
  532. ;      bx - drive number to report on.
  533. ;   es:di - transfer area for audio channel info
  534. ;
  535. ; Exit:
  536. ;   es:[di+0] - current input channel set for output channel 0 ( 0 or  1 )
  537. ;   es:[di+1] - current volume        set for output channel 0 ( 0 or -1 )
  538. ;   es:[di+2] - current input channel set for output channel 1 ( 0 or  1 )
  539. ;   es:[di+3] - current volume        set for output channel 1 ( 0 or -1 )
  540. ;   es:[di+4] - current input channel set for output channel 2 ( 0 )
  541. ;   es:[di+5] - current volume        set for output channel 2 ( 0 )
  542. ;   es:[di+6] - current input channel set for output channel 3 ( 1 )
  543. ;   es:[di+7] - current volume        set for output channel 3 ( 0 )
  544. ;
  545. ;----------------------------------------------------------------------
  546. cdrom_audio_channel_info proc near
  547.  
  548.         mov     al,cs:audio_vol[bx]
  549.  
  550.         or      al,al                   ;are both channels on?
  551.         jne     @f                      ;  no
  552.         mov     ax,0ffffh               ;  yes
  553.         jmp     short audio_channel_info_normal
  554. @@:
  555.         cmp     al,1                    ;is left channel on, right off?
  556.         jne     @f                      ;  no
  557.         mov     ax,0ffh                 ;  yes
  558.         jmp     short audio_channel_info_normal
  559. @@:
  560.         cmp     al,2                    ;is right channel on, left off?
  561.         jne     @f                      ;  no, both channels must be off
  562.         mov     ax,0ff00h               ;  yes
  563.         jmp     short audio_channel_info_normal
  564. @@:
  565.         xor     ax,ax
  566.  
  567. audio_channel_info_normal:
  568.         mov     cs:left_vol,al
  569.         mov     cs:right_vol,ah
  570.         mov     ax,cs
  571.         mov     ds,ax
  572.         mov     si,offset cs:audio_ch_work
  573.         mov     cx,audio_ch_work_size / 2
  574.         cld
  575.         rep     movsw                   ;store from audio_ch_work structure
  576.         ret
  577.  
  578. cdrom_audio_channel_info endp
  579.  
  580.  
  581. ;----------------------------------------------------------------------
  582. ;
  583. ; IOCTL INPUT sub-function #5
  584. ;
  585. ; Return the version of the drive.
  586. ;
  587. ; Entry:
  588. ;      bx - drive number
  589. ;   es:di - transfer address for version string.
  590. ;
  591. ; Exit:
  592. ;   carry clear - no error
  593. ;                 es:[di+0] = num bytes copied to es:[di+1]
  594. ;   carry set   - error
  595. ;                 es:[di+0] = 0
  596. ;
  597. ;----------------------------------------------------------------------
  598. cdrom_read_drive_bytes proc near
  599.  
  600.         mov     es:io_num_bytes[di],52  ;return number of bytes read
  601.         mov     ah,GET_DRIVE_VERSION
  602.         mov     dx,bx                   ;drive number in dl
  603.         mov     bx,di                   ;transfer address in 
  604.         inc     bx                      ;advance to 1st string character
  605.         call    CDREAD                  ;read version of CD-ROM drive 
  606.         jnc     @f                      ;error getting version string?
  607.         mov     es:io_num_bytes[di],0   ;  yes, say no bytes were read
  608. @@:     ret                             ;  no
  609.  
  610. cdrom_read_drive_bytes endp
  611.  
  612.  
  613. ;----------------------------------------------------------------------
  614. ;
  615. ; IOCTL INPUT sub-function #6 
  616. ;
  617. ; Return 32 bits of drive status information.
  618. ;
  619. ; These bits are constant ( 0x00000394 ):
  620. ;    Bit:
  621. ;       2  - 1 (reads both cooked and raw mode)
  622. ;       3  - 0 (read only device)
  623. ;       4  - 1 (can play audio tracks and data read)
  624. ;       5  - 0 (no interleaving support)
  625. ;       7  - 1 (prefetching support)
  626. ;       8  - 1 (audio channel manipulation allowed)
  627. ;       9  - 1 (both HSG and redbook addressing support)
  628. ;      12  - 0 (no P-W subchannel support)
  629. ;
  630. ; Entry:
  631. ;          bx - drive number
  632. ;       es:di - transfer address
  633. ;
  634. ; Exit:
  635. ;       carry - error occurred
  636. ;       no "  - dx:ax = device status
  637. ;
  638. ;----------------------------------------------------------------------
  639. cdrom_device_status proc near
  640.  
  641.         call    cdrom_drive_status
  642.         jnc     @f
  643.         jz      device_status_error
  644.         cmp     al,8ah                  ;focus error
  645.         jne     device_status_error
  646.         mov     cx,0800h                ;no disc in drive, door is closed
  647.         jmp     short device_status_door_closed
  648. @@:                                     ;no error so far
  649.         xor     cx,cx                   ;cx is temp device status bit field
  650.         test    al,20h                  ;disk changed ?
  651.         jz      @f                      ;  no
  652.         mov     cs:disc_changed[bx],1   ;  yes, set the disc changed flag
  653. @@:     test    al,40h                  ;is the door open?
  654.         jz      device_status_door_closed    ;  nope
  655.         mov     cs:disc_changed[bx],1   ;  yep, no disc in drive, door open
  656.         or      cx,801h
  657.  
  658. device_status_door_closed:
  659.         mov     ax,(PREVENT_ALLOW_CMD shl 8) ;al = 0 (read lock mode)
  660.         mov     dx,bx                   ;dx = drive number
  661.         call    CDREAD                  
  662.         jc      device_status_error     ;time out
  663.         test    al,1                    ;media is removable??
  664.         jnz     @f                      ;  nope, door is locked
  665.         or      cx,2                    ;  yes,  door is unlocked
  666. @@:     or      cx,394h                 ;set constant Hitachi device status
  667.         mov     ax,cx
  668.         xor     dx,dx
  669.         clc
  670.  
  671. device_status_exit:
  672.         ret
  673.  
  674. device_status_error:
  675.         stc                             ;time out or drive not ready error
  676.         jc      device_status_exit
  677.  
  678. cdrom_device_status endp
  679.  
  680.  
  681. ;----------------------------------------------------------------------
  682. ;
  683. ; IOCTL INPUT sub-function #7
  684. ;
  685. ; Return CD-ROM sector size for the passed read mode.  Since this must be
  686. ; 2048 for cooked, and 2352 for raw, it's handled by device independent code.
  687. ;
  688. ;----------------------------------------------------------------------
  689. ;----------------------------------------------------------------------
  690. ;
  691. ; IOCTL INPUT sub-function #8
  692. ;
  693. ; Return number of CD-ROM sectors available on the disc.  This is the 
  694. ; location of the lead out track in binary.  For example a lead-out track
  695. ; at 31:14.63 would yield (31 * 60 * 75) + (14 * 75) + 63 = 140613.
  696. ; Entry:
  697. ;          bx - drive number
  698. ;       es:di - transfer address
  699. ;
  700. ; Exit:
  701. ;       carry - error occurred, ax contains status code
  702. ;       no "  - dx:ax = volume size
  703. ;
  704. ;       trashes bx,cx,si,ds
  705. ;
  706. ;----------------------------------------------------------------------
  707. cdrom_volume_size proc near
  708.         push    es                      ;preserve the xfer address
  709.         push    di
  710.         sub     sp,6                    ;reserve a buffer for diskinfo
  711.         mov     ax,ss
  712.         mov     es,ax
  713.         mov     di,sp                   ;es:di points to buffer for diskinfo
  714.         call    cdrom_audio_diskinfo
  715.         jnc     @f                      ;error getting lead-out track?
  716.         add     sp,6                    ;revert the stack
  717.         stc                             ;set the error
  718.  
  719. volume_size_exit:
  720.         pop     di                      ;revert the xfer addr
  721.         pop     es                      
  722.         
  723.         ret
  724.  
  725. @@:
  726.         mov     bp,sp
  727.         mov     dx,[bp+4]               ;no, get redbook addr of lead-out...
  728.         mov     ax,[bp+2]
  729.         call    red2hsg                 ;...convert it to HSG addr
  730.  
  731.         sub     ax,1                    ; the lead out addr is 1 greater than
  732.         sbb     dx,0                    ; the last sector
  733.  
  734.         add     sp,6                    ;revert the stack
  735.         clc                             
  736.         jmp     short volume_size_exit
  737.  
  738. cdrom_volume_size endp
  739.  
  740.  
  741. ;----------------------------------------------------------------------
  742. ;
  743. ; IOCTL INPUT sub-function #9
  744. ;
  745. ; Entry:
  746. ;       bx = drive num
  747. ;
  748. ; Exit:
  749. ;       carry set   - error occurred, al is invalid
  750. ;       carry clear - al =  1 - not changed, -1 - changed, 0 - can't tell
  751. ;       trashes cl
  752. ;
  753. ;----------------------------------------------------------------------
  754. cdrom_media_changed proc near
  755.  
  756.         mov     cl,1                    ;assume didn't changed
  757.         call    cdrom_drive_status
  758.         jc      @f                      ;drive not ready?
  759.         mov     al,cs:disc_changed[bx]  ;get disc change flag..
  760.         mov     cs:disc_changed[bx],0   ;..and reset it (now they know)
  761.         or      al,al                   ; disc changed?
  762.         jz      @f                      ;   no, go report it
  763.         mov     cl,-1                   ;   maybe, make sure..
  764.         cmp     al,1                    ; ..disc changed?
  765.         je      @f                      ;     yep
  766.         xor     cl,cl                   ;     no, don't know what's going on
  767. @@:     mov     al,cl                   ;return media changed flag in al
  768.         ret
  769.  
  770. cdrom_media_changed endp
  771.  
  772.  
  773. ;----------------------------------------------------------------------
  774. ;
  775. ; IOCTL INPUT sub-function #10
  776. ;
  777. ; Report the binary value of the lowest and highest track, and the redbook
  778. ; address of the lead-out track as recorded in the Q-channel of the 
  779. ; lead-in track.
  780. ;
  781. ; Note Hitachi code below will cause a seek to lead-in area to get this
  782. ; information, only if not previously reported for the current disc.
  783. ;
  784. ; Entry:
  785. ;       bx - drive num
  786. ;    es:di - application buffer for disk info
  787. ;
  788. ; Entry:
  789. ;       carry set   - error occurred, ax contains status word
  790. ;       carry clear - first track, last track, start of lead-out copied
  791. ;       trashes bx,cx,si,di,ds
  792. ;
  793. ;----------------------------------------------------------------------
  794. cdrom_audio_diskinfo proc near
  795.  
  796.         mov     cs:a_flag,0
  797.  
  798. get_audio_track_entry:
  799. ;
  800. ; a_flag: 0 - called from audio_diskinfo
  801. ;         1 - called from audio_trackinfo
  802. ;
  803.         call    cdrom_drive_status
  804.         jnc     @f                      ;not ready error?
  805.  
  806. audio_diskinfo_not_ready:
  807.         mov     ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
  808.  
  809. audio_diskinfo_error:
  810.         stc
  811.         ret
  812. @@:
  813.         mov     scans,SCAN_COUNT        ;scan default number til see a0/a1/a2
  814.         mov     ax,es                   ;preserve application's..
  815.         mov     word ptr app_xfer_buffer+2,ax    ;..transfer..
  816.         mov     word ptr app_xfer_buffer,di      ;..address
  817.         mov     dx,bx
  818.         mov     bp,offset toc_table
  819.         mov     ax,cs
  820.         mov     es,ax
  821.         mov     ds,ax
  822.         mov     bx,offset qbuf
  823. ;
  824. ; register usage in loops below:
  825. ;
  826. ;    dx = drive number for all drive calls below
  827. ;    bp = toc_table base for resetting di
  828. ;    bx = qbuf base for resetting si and to pass to the drive
  829. ; ds:si = current offset into qbuf (Qchannel buffer)
  830. ; es:di = current offset into toc_table (table of contents buffer)
  831. ;
  832.         cmp     dl,cs:toc_drive         ;do we already know this toc?
  833.         jne     @f                      ;  no, have to init toc_table
  834.         jmp     audio_diskinfo_same     ;  yes
  835. @@:
  836.         mov     cs:toc_drive,0ffh       ;reset drive flag (none current)
  837.         mov     si,bp
  838.         add     si,point_x              ;get loc of first point_x
  839.         mov     cx,3+99                 ;zero all point's to tell when all..
  840.         xor     ax,ax                   ;..track locations have been init'd 
  841. @@:     mov     [si],al
  842.         add     si,size _QchanInfo
  843.         loop    @b
  844. ;
  845. ; Head of retry loop
  846. ;
  847.         mov     i1,RETRY_COUNT
  848.  
  849. audio_diskinfo_i1_loop:
  850.         mov     ah,SEEK_LEADIN_CMD      ;Seek to lead-in track
  851.         call    CDREAD
  852.         jc      audio_diskinfo_not_ready
  853. ;
  854. ; init Q-channel info in the last iteration to a value we won't ever see
  855. ;
  856.         mov     last_point,0ffh
  857. ;
  858. ; head of loop scanning for new entries
  859. ;
  860.         mov     i2,0
  861.  
  862. audio_diskinfo_i2_loop:
  863.         mov     cs:loc_cnt,900          ;about 10 seconds
  864.  
  865. audio_diskinfo_loop_Q:
  866.         mov     ah,READ_Q_CMD           ;read 10 Q-channel bytes
  867.         call    CDREAD
  868.         jc      audio_diskinfo_not_ready
  869.         mov     al,[bx].point_x         ;get which Q-channel byte this is
  870.         cmp     al,last_point           ;is it the same as the last iteration?
  871.         je      audio_diskinfo_next_Q   ;  yep, keep looking
  872.         mov     cl,[bx].ctrl_adr        ;  nope, get ctrl info
  873.         cmp     cl,0FFh                 ;still seeking to lead_in?
  874.         je      audio_diskinfo_next_Q   ;  yes, try again
  875.         and     cl,0Fh                  ;  no, mask off ADR
  876.         cmp     cl,1                    ;is it a TOC entry?
  877.         jne     audio_diskinfo_next_Q   ;  no, ignore ADR = 2 or 3
  878.         mov     last_point,al           ;  yes, got a new entry, remember it
  879.         cmp     [bx].tno,0              ;still in the lead-in track?
  880.         jne     audio_diskinfo_done     ; no, get out and try again
  881.         cmp     al,0A0h                 ;  yes, is it one of a0/a1/a2?
  882.         je      @f                      ;    yes
  883.         cmp     al,0A1h
  884.         je      @f                      ;    yes
  885.         cmp     al,0A2h
  886.         je      @f                      ;    yes
  887. ;
  888. ; not a0/a1/a2, must be audio track info, convert to binary
  889. ;
  890.         call    bcd2bin
  891.         jc      audio_diskinfo_done     ;bogus value, get out, try again
  892. ;
  893. ; first 3 entries in toc_table are for a0/a1/a2
  894. ; other 99 are for track info. track 1 starts at offset 3
  895. ;
  896.         add     ax,3 - 1                ;skip over first/last track record
  897.         jmp     short audio_diskinfo_store_qbuf
  898.  
  899. audio_diskinfo_next_Q:
  900.         dec     cs:loc_cnt
  901.         jnz     audio_diskinfo_loop_Q
  902.         jmp     audio_diskinfo_next_i1  ;still didn't find a0/a1/a2, go retry
  903. @@:
  904. ;
  905. ; Handle a0/a1/a2 entries here.
  906. ; If we see a2, check if a0 and a1 already seen
  907. ; If both seen, we know how many tracks are on the CD
  908. ; so we can decrease the number of entries we have to read
  909. ;
  910.         push    ax
  911.         cmp     al,0A2h                 ;is this a2 entry?
  912.         jne     @f                      ;  no, handle normal
  913.         mov     di,bp                   ;  yes, check if a0 and a1 entries seen
  914.         cmp     [di].point_x,0          ;entry is seen if point_x is non-zero
  915.         je      @f
  916.         cmp     [di + size _QchanInfo].point_x,0
  917.         je      @f
  918. ;
  919. ; a0 and a1 are read, calculate how many more entries we have
  920. ; to read before getting the entire TOC 
  921. ;
  922.         mov     al,[di + size _QchanInfo].pmin
  923.         call    bcd2bin
  924.         mov     cx,ax
  925.         mov     al,[di].pmin
  926.         call    bcd2bin
  927.         sub     cx,ax
  928.         add     cx,1+3
  929.         mov     scans,cx                ;last - first + 1 + 3 (for a0/a1/a2)
  930. @@:
  931.         pop     ax                      ;restore a0/a1/a2
  932.         sub     al,0A0h                 ;calc offset into toc_table
  933.  
  934. audio_diskinfo_store_qbuf:
  935.         mov     cx,size _QchanInfo
  936.         imul    cl                      ;ax is offset from base of toc_table
  937.         mov     di,bp
  938.         add     di,ax                   ;es:di -> where to store new entry at
  939.         mov     si,bx                   ;ds:si -> new entry
  940.         mov     cx,(size _QchanInfo) / 2;copy 10 bytes
  941.         rep     movsw
  942.         
  943.         mov     cx,scans                ;check if we are done scanning table
  944.         cmp     i2,cx                   ;copied > default or num in table?
  945.         jae     audio_diskinfo_done     ;  yep, exit
  946.         inc     i2                      ;  nope
  947.         jmp     audio_diskinfo_i2_loop
  948.  
  949. audio_diskinfo_done:
  950. ;
  951. ; make sure all qchannel entries are read in and are valid
  952. ;
  953. ; first see if a0/a1/a2 are valid
  954. ;
  955.         mov     di,bp                   ;get back base of toc_table
  956.         cmp     [di].point_x,0
  957.         je      audio_diskinfo_not_done
  958.         cmp     [di + size _QchanInfo].point_x,0
  959.         je      audio_diskinfo_not_done
  960.         cmp     [di + (size _QchanInfo * 2)].point_x,0
  961.         je      audio_diskinfo_not_done
  962. ;
  963. ; a0/a1/a2 valid, we can calculate the number of entries in toc_table
  964. ; where number of entries is last - (first - 1)
  965. ;
  966.         mov     al,[di + size _QchanInfo].pmin
  967.         call    bcd2bin
  968.         mov     cx,ax                   ;cx = last
  969.         mov     al,[di].pmin            ;ax = first
  970.         call    bcd2bin
  971.         dec     ax
  972.         sub     cx,ax                   ;cx is num entries, ax is first - 1
  973. ;
  974. ; Calc offset in toc_table to start scanning from:
  975. ; (offset toc_table) + ((first-1+3) * size _QchanInfo)
  976. ;
  977.         add     ax,3
  978.         mov     dh,size _QchanInfo
  979.         imul    dh
  980.         add     di,ax
  981.         add     di,point_x              ;add offset of point_x
  982. @@:                                     ;verify that all point_x's are filled
  983.         cmp     byte ptr [di],0
  984.         jz      audio_diskinfo_not_done
  985.         add     di,(size _QchanInfo)
  986.         loop    @b
  987.         jmp     short audio_diskinfo_valid
  988.  
  989. audio_diskinfo_not_done:
  990. ;
  991. ; at least one Q-channel entry isn't valid
  992. ;
  993.         cmp     i2,250                  ;get another Q-channel entry?
  994.         jae     audio_diskinfo_next_i1  ;  no, retry from lead-in track
  995.         jmp     audio_diskinfo_i2_loop  ;  yes
  996.  
  997. audio_diskinfo_next_i1:
  998.         dec     i1                      ;ok to retry at lead-in track again?
  999.         jz      @f                      ;  nope, drive must not be ready
  1000.         jmp     audio_diskinfo_i1_loop  ;  yes, give the drive another chance
  1001. @@:
  1002.         mov     ah,PAUSE_CMD
  1003.         call    CDREAD
  1004.         jmp     audio_diskinfo_not_ready
  1005.  
  1006. audio_diskinfo_valid:
  1007.         mov     ah,PAUSE_CMD
  1008.         call    CDREAD                  ;perform the pause
  1009.         jnc     audio_diskinfo_same
  1010.         jmp     audio_diskinfo_not_ready;geez, and we almost made it too
  1011.  
  1012. audio_diskinfo_same:
  1013. ;
  1014. ; The table is complete, copy the a0/a1/a2 results back to user
  1015. ;
  1016.         mov     es,word ptr app_xfer_buffer+2 ; restore app's transfer addr
  1017.         mov     di,word ptr app_xfer_buffer
  1018.  
  1019.         mov     cs:toc_drive,dl         ;now we know this toc
  1020. ;
  1021. ; if really called from audio_trackinfo return there
  1022. ;
  1023.         cmp     cs:a_flag,0
  1024.         je      @f                      ;  nope, it's audio_diskinfo time
  1025.         jmp     short audio_trackinfo_return  ;  yep,  we're done
  1026. @@:
  1027.         mov     si,(offset toc_table + pmin) ;ds:si is addr of a0 pmin
  1028.         mov     al,[si]                 ;get first track no (a0)
  1029.         call    bcd2bin
  1030.         stosb                           ;copy first track number
  1031.         mov     al,[si + size _QchanInfo];get last track no (a1)
  1032.         call    bcd2bin
  1033.         stosb                           ;copy last track number
  1034.         add     si,size _QchanInfo * 2  ;ds:si is addr of a2 pmin/psec/pframe
  1035.         mov     dl,ds:[si]              ;Convert from bcd to binary red book
  1036.         mov     ax,ds:[si+1]
  1037.         xchg    al,ah
  1038.         call    bcd2red
  1039.         stosw                           ;copy address of lead-out track
  1040.         mov     ax,dx
  1041.         stosw
  1042.         clc
  1043.         ret
  1044.  
  1045. cdrom_audio_diskinfo endp
  1046.  
  1047.  
  1048. ;----------------------------------------------------------------------
  1049. ;
  1050. ; IOCTL INPUT sub-function #11
  1051. ;
  1052. ; Return the redbook address of the passed binary track number, and the
  1053. ; track control information byte.
  1054. ;
  1055. ; Takes the track number desired and looks up the toc_table information
  1056. ; If the disc has been changed since the last time this information was
  1057. ; retrieved the toc_table will be rebuilt.
  1058. ;
  1059. ; Entry:
  1060. ;          bx - drive num
  1061. ;       es:di - application buffer for track info
  1062. ;
  1063. ; Entry:
  1064. ;       carry set   - error occurred, ax contains status word
  1065. ;       carry clear - starting point of track and control info copied
  1066. ;       trashes bx,cx,si,di,ds
  1067. ;
  1068. ;----------------------------------------------------------------------
  1069. cdrom_audio_trackinfo proc near
  1070.  
  1071.         mov     cs:a_flag,1
  1072.         jmp     get_audio_track_entry
  1073.  
  1074. audio_trackinfo_return:
  1075. ;
  1076. ; returns with ds set to cs
  1077. ;
  1078.         xor     cx,cx
  1079.         mov     cl,es:[di]              ;cx = passed track number
  1080.         inc     di                      ;get to redbook address xfer area
  1081.         mov     si,offset toc_table
  1082. ;
  1083. ; make sure the track they're asking about is not before the first
  1084. ; one, or after the last one
  1085. ;
  1086.         mov     al,[si].pmin
  1087.         call    bcd2bin
  1088.         cmp     cl,al                   ;before the first track?
  1089.         jb      audio_trackinfo_error   ;  yes
  1090.         mov     al,[si+size _QchanInfo].pmin
  1091.         call    bcd2bin
  1092.         cmp     cl,al                   ;after the last track?
  1093.         ja      audio_trackinfo_error   ;  yes
  1094.         dec     cx                      ;  no, make 1->0,...,99->98
  1095. ;
  1096. ; offset into toc_table for inquired track number
  1097. ;
  1098.         mov     ax,size _QchanInfo
  1099.         imul    cx
  1100.         add     ax,size _QchanInfo * 3  ;skip a0/a1/a2 entries
  1101.         add     si,ax                   ;ds:si addr of entry we want
  1102.         mov     dl,[si].pmin
  1103.         mov     ah,[si].psec
  1104.         mov     al,[si].pframe
  1105.         call    bcd2red
  1106.         mov     es:[di],ax
  1107.         mov     es:[di+2],dx
  1108.         mov     al,[si].ctrl_adr        ;get ctrl info for track
  1109.         mov     es:[di+4],al
  1110.         clc
  1111.         ret
  1112.  
  1113. audio_trackinfo_error:
  1114.         mov     ax,(ERRBIT + DONEBIT + drverr_general_failure)
  1115.         stc
  1116.         ret
  1117.  
  1118. cdrom_audio_trackinfo endp
  1119.  
  1120.  
  1121. ;----------------------------------------------------------------------
  1122. ;
  1123. ; IOCTL INPUT sub-function #12
  1124. ;
  1125. ; Return the current Q-channel address in redbook.
  1126. ;
  1127. ; Note the operation of this function *should not* change the current
  1128. ; drive status, as it can be used to monitor the current head location.
  1129. ; Therefore, it should be successful even if the drive is currently idle.
  1130. ; Note the CONTROL/ADR and POINT/Index bytes are returned verbatim,
  1131. ; and if ADR is not 1, the address of the head location is not translated
  1132. ; to redbook since in this case it is either the UPC bytes or.
  1133. ; Entry:
  1134. ;          bx - drive num
  1135. ;       es:di - application buffer for Qchannel info
  1136. ;
  1137. ; Exit:
  1138. ;       carry set   - error occurred, ax contains status word
  1139. ;       carry clear - Qchannel info was copied
  1140. ;       trashes bx,cx,si,di,bp,ds
  1141. ;
  1142. ;----------------------------------------------------------------------
  1143. cdrom_audio_Qchannel proc near
  1144.  
  1145.         mov     cs:scans,CNT3           ;set loop limit
  1146.         mov     dx,bx                   ;dx = drive number
  1147.         mov     ax,cs
  1148.         mov     ds,ax
  1149.         mov     si,offset cs:qbuf
  1150. ;
  1151. ; ds:si - qbuf
  1152. ; es:di - xfer addr
  1153. ;    dx - drive num
  1154.  
  1155. cda_Qchannel_retry:
  1156.         push    es
  1157.         mov     ax,cs
  1158.         mov     es,ax
  1159.         mov     bx,si
  1160.         mov     ah,READ_Q_CMD
  1161.         call    CDREAD                  ;read subcode-Q (TOC)
  1162.         pop     es                      ;restore xfer segment address
  1163.         jnc     @f
  1164.  
  1165. cda_Qchannel_error:
  1166.         mov     ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
  1167.         stc
  1168.         ret
  1169. @@:
  1170.         dec     cs:scans                ;timeout?
  1171.         jz      cda_Qchannel_error      ;  yes
  1172.  
  1173.         mov     al,[si].ctrl_adr
  1174.         cmp     al,0FFh                 ;Invalid CONTROL/ADR??
  1175.         je      cda_Qchannel_retry      ;  yes
  1176. ;
  1177. ; set cx = flag for whether to xlat times to redbook
  1178. ; no xlat is necessary if ADR is 2 (UPC bytes), or ADR is 3 ( ? )
  1179. ;
  1180.         mov     cx,1                    ;assume xlat
  1181.         and     al,0Fh                  ;did we read a qchannel address..
  1182.         cmp     al,01h                  ;..in that sector?
  1183.         je      @f                      ;  yes
  1184.         xor     cx,cx                   ;  no, don't need to xlat to redbook
  1185. @@:
  1186. ;
  1187. ; copy Qchannel buffer to the request header (xlat BCD addresses if required)
  1188. ;
  1189.         movsb                           ;CONTROL and ADR byte
  1190.         movsw                           ;track num byte, and point_x byte
  1191.         mov     bp,2                    ;copy two times (running and absolute)
  1192.  
  1193. cda_Qchannel_disk_time:
  1194.         lodsb
  1195.         mov     dl,al
  1196.         lodsw
  1197.         or      cx,cx
  1198.         je      @f
  1199.         xchg    al,ah
  1200.         call    bcd2red
  1201. @@:     xchg    al,ah
  1202.         xchg    al,dl
  1203.         stosb
  1204.         xchg    al,dl
  1205.         stosw
  1206.         dec     bp
  1207.         jz      cda_Qchannel_exit
  1208.         movsb                           ;copy the zero
  1209.         jmp     short cda_Qchannel_disk_time
  1210.  
  1211. cda_Qchannel_exit:
  1212.         clc
  1213.         ret
  1214.  
  1215. cdrom_audio_Qchannel endp
  1216.  
  1217.  
  1218. ;----------------------------------------------------------------------
  1219. ;
  1220. ; IOCTL INPUT sub-function #13
  1221. ;
  1222. ; Returns the sub-channel information from the contiguous frames (sectors)
  1223. ; requested starting at the passed redbook address.  The sub-channels are
  1224. ; not decoded, that is, P is the MSB and W is the LSB in each byte.
  1225. ;
  1226. ; This command is be supported by Hitachi drive hardware.
  1227. ;
  1228. ; Entry:
  1229. ;          bx - drive num
  1230. ;       es:di - application buffer for sub-channel bytes
  1231. ;
  1232. ; Exit:
  1233. ;       carry set   - error occurred, ax contains status word
  1234. ;       carry clear - sub-channel bytes were copied
  1235. ;
  1236. ;----------------------------------------------------------------------
  1237. cdrom_audio_Subchannel proc near
  1238.  
  1239. ; This command should be supported!
  1240. ;
  1241.         mov     ax,(ERRBIT + DONEBIT + drverr_unknown_command)
  1242.         stc
  1243.         ret
  1244.  
  1245. cdrom_audio_Subchannel endp
  1246.  
  1247.  
  1248. ;----------------------------------------------------------------------
  1249. ;
  1250. ; IOCTL INPUT sub-function #14
  1251. ;
  1252. ; Return the Universal Product Code of the disc.  This is located in 10
  1253. ; contiguous bytes of the Q-channel (ie., in one frame out of every 100),
  1254. ; and identified with an ADR value of 2.
  1255. ;
  1256. ; Entry:
  1257. ;          bx - drive num
  1258. ;       es:di - application buffer for UPC bytes
  1259. ;
  1260. ; Exit:
  1261. ;       carry set   - error occurred, ax contains status word
  1262. ;       carry clear - UPC bytes were copied
  1263. ;
  1264. ;----------------------------------------------------------------------
  1265. cdrom_upc_code proc near
  1266.  
  1267.  
  1268. ; If the head is not moving, the upc information won't be a part of the
  1269. ; Qchannel information, so we seek to the lead in track
  1270.  
  1271.         call    cdrom_drive_status      ;busy with audio?
  1272.         jc      upc_disk_error          ;   drive not ready
  1273.         and     al,04h                  ;   audio playing?
  1274.         jnz     @f                      ;       yes? continue w/init
  1275.  
  1276.         mov     ah,SEEK_LEADIN_CMD      ;   audio not playing?
  1277.         call    CDREAD                  ;       Seek to lead in
  1278.         jc      upc_disk_error
  1279.         
  1280. @@:     
  1281.         mov     cs:scans, UPC_COUNT     ; Repeat count
  1282.         mov     dx,bx
  1283.         mov     ax,cs
  1284.         mov     ds,ax
  1285.         mov     si,offset cs:qbuf       
  1286.  
  1287. ;
  1288. ; ds:si - qbuf
  1289. ; es:di - xfer addr
  1290. ;    dx - drive num
  1291. ;
  1292.  
  1293. upc_retry:                              ; loop to retry
  1294.  
  1295.         push    es
  1296.         mov     ax,cs
  1297.         mov     es,ax
  1298.         mov     bx,si
  1299.         mov     ah,READ_Q_CMD           ; Call the Qchannel read
  1300.         call    CDREAD
  1301.         pop     es
  1302.         jnc     @f
  1303.  
  1304. upc_disk_error:                         ; Problem with the read
  1305.         mov     ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
  1306.         stc
  1307.         ret
  1308.  
  1309. @@:
  1310.         mov     al,[si].ctrl_adr        ; ADR == 2 means this
  1311.         and     al,0fh                  ; subcode block has UPC
  1312.         cmp     al,2                    
  1313.         je      upc_return              ;   yes? return the block
  1314.         
  1315.         dec     cs:scans
  1316.         jnz     upc_retry               ; try again or fall through
  1317.  
  1318. ; UPC code was missed or non-existant
  1319. ;
  1320. ; fall through, returns sector_not_found
  1321. ;
  1322.         mov     ax,(ERRBIT + DONEBIT + drverr_sector_not_found)
  1323.         stc
  1324.         ret
  1325.  
  1326. ; returns upc info
  1327.  
  1328. upc_return:
  1329.         mov     cx,(size _QchanInfo /2) ; Word copy the UPC information
  1330.         rep     movsw                   ;  into the xfer 
  1331.         clc
  1332.         ret
  1333.  
  1334. cdrom_upc_code endp
  1335.  
  1336.  
  1337. ;----------------------------------------------------------------------
  1338. ;
  1339. ; IOCTL INPUT sub-function #15
  1340. ;
  1341. ;
  1342. ; Return audio status information.  This is called from the device
  1343. ; independent code to ask whether the drive door is open.  The PLAY AUDIO
  1344. ; command should lock the drive door closed, but if this is overridden (if
  1345. ; the door can be opened manually) this call should check if the door is
  1346. ; open and return carry set if it is.
  1347. ; Entry:
  1348. ;       bx - drive num
  1349. ;
  1350. ; Exit:
  1351. ;       carry set   - door is open or error occurred
  1352. ;       carry clear - door is closed
  1353. ;
  1354. ;----------------------------------------------------------------------
  1355. cdrom_audio_status_info proc near
  1356.  
  1357.         call    cdrom_drive_status      ;error occurred?
  1358.         jc      @f                      ;  yes
  1359.         test    al,40h                  ;  no, door open?
  1360.         jz      @f                      ;    no
  1361.         stc                             ;    yes
  1362. @@:     ret
  1363.  
  1364. cdrom_audio_status_info endp
  1365.  
  1366.  
  1367. ;============================================================
  1368. ;
  1369. ; IOCTL OUTPUT commands...
  1370. ;
  1371. ;============================================================
  1372.  
  1373. ;----------------------------------------------------------------------
  1374. ;
  1375. ; IOCTL OUTPUT sub-function #0
  1376. ;
  1377. ; Unlock the drive door and eject the disc.
  1378. ;
  1379. ; Note that after successful completion of this command the status bit
  1380. ; in the device status word should report the door as being open until the
  1381. ; user has inserted a disc and closed the door (so the door open bit
  1382. ; can be monitored until this has occurred).
  1383. ;
  1384. ; Entry:
  1385. ;       bx - drive num
  1386. ;
  1387. ; Exit:
  1388. ;       carry set   - error occurred, ax contains status word
  1389. ;       carry clear - ejected OK
  1390. ;
  1391. ;----------------------------------------------------------------------
  1392. cdrom_eject proc near
  1393.  
  1394.         mov     dx,bx                   ;dx = drive number
  1395.         mov     ax,( (PREVENT_ALLOW_CMD shl 8) + 2 )
  1396.         call    CDREAD                  ;unlock the door please
  1397.         jc      cdrom_eject_drive_not_ready
  1398.         test    al,01h                  ;media is removable?
  1399.         jz      @f                      ;  yes (door currently unlocked)
  1400.         mov     ax,(ERRBIT + DONEBIT + drverr_invalid_disc_change)
  1401.         stc
  1402.         jc      cdrom_eject_exit
  1403. @@:
  1404.         mov     ah,OPENDOOR_CMD
  1405.         call    CDREAD                  ;Open door
  1406. ;
  1407. ; if carry is clear no error occurred and what's in ax is ignored
  1408. ;
  1409. cdrom_eject_drive_not_ready:
  1410.         mov     ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
  1411.  
  1412. cdrom_eject_exit:
  1413.         ret
  1414.  
  1415. cdrom_eject endp
  1416.  
  1417.  
  1418. ;----------------------------------------------------------------------
  1419. ;
  1420. ; IOCTL OUTPUT sub-function #1
  1421. ;
  1422. ; Unlock/lock the drive door.
  1423. ;
  1424. ; Entry:
  1425. ;       bx - drive num
  1426. ;       al - lock/unlock code byte (0 - unlock door, 1 - lock door)
  1427. ;
  1428. ; Exit:
  1429. ;       carry set   - error occurred, ax contains status word
  1430. ;       carry clear - requested locking function completed OK
  1431. ;
  1432. ;----------------------------------------------------------------------
  1433. cdrom_lock_door proc near
  1434.  
  1435.         mov     dx,bx                   ;dx = drive number
  1436.         cmp     al,1                    ;lock the door?
  1437.         je      @f                      ;  yes
  1438.         mov     al,2                    ;  no
  1439. @@:
  1440.         mov     ah,PREVENT_ALLOW_CMD    ;al = 1 - set lock mode, or
  1441.         call    CDREAD                  ;   = 2 - set unlock mode
  1442. ;
  1443. ; if carry is clear no error occurred and what's in ax is ignored
  1444. ;
  1445.         mov     ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
  1446.         ret
  1447.  
  1448. cdrom_lock_door endp
  1449.  
  1450.  
  1451. ;----------------------------------------------------------------------
  1452. ;
  1453. ; IOCTL OUTPUT sub-function #2
  1454. ;
  1455. ; Tell the drive to reset and re-initialize itself.  What happens here
  1456. ; is, of course, entirely driver/hardware dependent.
  1457. ;
  1458. ; Entry:
  1459. ;       bx - drive num
  1460. ;
  1461. ; Exit:
  1462. ;       carry set   - error occurred, ax contains status word
  1463. ;       carry clear - reset OK
  1464. ;
  1465. ;----------------------------------------------------------------------
  1466. cdrom_reset_drive proc near
  1467.  
  1468.         mov     dx,bx                   ;dx = drive number
  1469.         mov     ah,RESET_CMD
  1470.         call    CDREAD
  1471. ;
  1472. ; if carry is clear no error occurred and what's in ax is ignored
  1473. ;
  1474.         mov     ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
  1475.         ret
  1476.  
  1477. cdrom_reset_drive endp
  1478.  
  1479.  
  1480. ;----------------------------------------------------------------------
  1481. ;
  1482. ; IOCTL OUTPUT sub-function #3
  1483. ;
  1484. ; Control audio channel output.
  1485. ;
  1486. ; Drives that support audio volume control distribute the number of settings
  1487. ; continuously across 256 values (eg. 16 settings become 0, 16, 32, ...).
  1488. ;
  1489. ; Drives than can't swap channels ignore channel swapping unless requested
  1490. ; to play both channels in one, in which case the other is suppressed.
  1491. ;
  1492. ; Drives that don't support four audio channels should ignore setting
  1493. ; specified for the second pair of channels.
  1494. ;
  1495. ; Entry:
  1496. ;       bx - drive num
  1497. ;       cl - output channel for input channel 0
  1498. ;       ch - channel 0 volume setting
  1499. ;       dl - output channel for input channel 1
  1500. ;       dh - channel 1 volume setting
  1501. ;       si - lo byte = output channel for input channel 2
  1502. ;            hi byte = channel 2 volume
  1503. ;       di - lo byte = output channel for input channel 3
  1504. ;            hi byte = channel 3 volume
  1505. ;
  1506. ; Exit:
  1507. ;       carry set   - error occurred, ax contains status word
  1508. ;       carry clear - reset OK
  1509. ;
  1510. ;----------------------------------------------------------------------
  1511. cdrom_audio_channel_ctrl proc near
  1512.  
  1513. ; init the volume settings
  1514. ;
  1515.         mov     cs:left_vol,ch
  1516.         mov     cs:right_vol,dh
  1517. ;
  1518. ; see if they are playing both channels in one
  1519. ; (Hitachi doesn't support redirecting channels so simulates it)
  1520. ;
  1521.         cmp     cl,dl
  1522.         jne     audio_channel_ctrl_set  ;  nope
  1523.         cmp     cl,1                    ;  yes, but is it 0 or 1?
  1524.         ja      audio_channel_ctrl_set  ;    no
  1525.         je      @f                      ;    yes, shut off channel 0?
  1526.         mov     cs:left_vol,0           ;      yes
  1527.         jmp     short audio_channel_ctrl_set
  1528. @@:     mov     cs:right_vol,0          ;      no, shut off channel 1
  1529.  
  1530. audio_channel_ctrl_set:
  1531. ;
  1532. ; setup the output volume levels code in al
  1533. ;
  1534.         mov     ch,cs:left_vol
  1535.         mov     cl,cs:right_vol
  1536.         mov     al,3                    ;assume both channels are off
  1537.         or      ch,ch                   ;is left channel on?
  1538.         jz      @f                      ;  no
  1539.         and     al,1                    ;  yes
  1540. @@:     or      cl,cl                   ;is right channel on?
  1541.         jz      @f                      ;  no
  1542.         and     al,2                    ;  yes, shut off bit 0
  1543. @@:
  1544.         mov     cs:audio_vol[bx],al
  1545.         mov     dx,bx                   ;dx = drive number
  1546.         mov     ah,AUDIO_CHANNEL_CTL    ;al = volume settings
  1547.         call    CDREAD
  1548. ;
  1549. ; if carry is clear no error occurred and what's in ax is ignored
  1550. ;
  1551.         mov     ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
  1552.         ret
  1553.  
  1554. cdrom_audio_channel_ctrl endp
  1555.  
  1556.  
  1557. ;----------------------------------------------------------------------
  1558. ;
  1559. ; IOCTL OUTPUT sub-function #4
  1560. ;
  1561. ; Write bytes directly to the CD-ROM drive.
  1562. ;
  1563. ; This routine is provided to allow device and/or driver dependent
  1564. ; information (not addressed elsewhere in the MSCDEX device driver spec)
  1565. ; to be sent by an application.
  1566. ;
  1567. ;
  1568. ; Entry:
  1569. ;          bx - drive num
  1570. ;       es:di - application buffer for drive specific data
  1571. ;
  1572. ; Exit:
  1573. ;       carry set   - error occurred, ax contains status word
  1574. ;       carry clear - set drive data OK
  1575. ;
  1576. ;----------------------------------------------------------------------
  1577. cdrom_write_drive_ctrl proc near
  1578.  
  1579.         mov     al,es:ioo_wrdev_top[di]
  1580.         or      al,al                           ;top data byte=0?
  1581.         jne     write_drive_ctrl_unknown_command; no
  1582.                                                 ; yes, 1st 3 bytes = 'HIT'?
  1583.         cmp     byte ptr es:ioo_wrdev_char[di],'H'
  1584.         jne     write_drive_ctrl_unknown_command
  1585.         cmp     word ptr es:ioo_wrdev_char[di+2],'TI'
  1586.         jne     write_drive_ctrl_unknown_command;   no
  1587.         push    si                              ;   yes
  1588.         push    di           
  1589.         push    es           
  1590.         mov     ax,es:ioo_wrdev_data[di]        ;setup registers
  1591.         mov     bx,es:ioo_wrdev_data[di+2]
  1592.         mov     cx,es:ioo_wrdev_data[di+4]
  1593.         mov     dx,es:ioo_wrdev_data[di+6]
  1594.         mov     si,es:ioo_wrdev_data[di+8]
  1595.         push    ax
  1596.         mov     ax,es:ioo_wrdev_data[di+12]
  1597.         mov     di,es:ioo_wrdev_data[di+10]
  1598.         mov     es,ax
  1599.         pop     ax           
  1600.         call    CDREAD
  1601.         pop     es           
  1602.         pop     di           
  1603.         pop     si          
  1604. ;
  1605. ; if carry is clear no error occurred and what's in ax is ignored
  1606. ;
  1607. write_drive_ctrl_drive_not_ready:
  1608.         mov     ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
  1609.         ret
  1610.  
  1611. write_drive_ctrl_unknown_command:
  1612.         mov     ax,(ERRBIT + DONEBIT + drverr_unknown_command)
  1613.         ret
  1614.  
  1615. cdrom_write_drive_ctrl endp
  1616.  
  1617.  
  1618. ;----------------------------------------------------------------------
  1619. ;
  1620. ; IOCTL OUTPUT sub-function #5
  1621. ;
  1622. ; Close the drive door.  This is the logical complement to the eject
  1623. ; command (IOCTL OUTPUT sub-function #0)
  1624. ;
  1625. ; Entry:
  1626. ;       bx - drive num
  1627. ;
  1628. ; Exit:
  1629. ;       carry set   - error occurred, ax contains status word
  1630. ;       carry clear - closed tray OK
  1631. ;
  1632. ;----------------------------------------------------------------------
  1633. cdrom_close_tray proc near
  1634.  
  1635.         mov     dx,bx
  1636.         mov     ah,CLOSEDOOR_CMD
  1637.         call    CDREAD                  ;Open door
  1638.         mov     ax,(ERRBIT + DONEBIT + drverr_drive_not_ready)
  1639. ;
  1640. ; if carry is clear no error occurred and what's in ax is ignored
  1641. ;
  1642.         ret
  1643.  
  1644. cdrom_close_tray endp
  1645.  
  1646.  
  1647. ;============================================================
  1648. ;
  1649. ; INPUT FLUSH command
  1650. ;
  1651. ; Free all input buffers and clear any pending requests.
  1652. ;
  1653. ;============================================================
  1654. cdrom_input_flush proc near
  1655.  
  1656. ; This device driver doesn't buffer any I/O and all I/O requests are
  1657. ; synchronous calls
  1658. ;
  1659.         stc
  1660.         mov     ax,(ERRBIT + DONEBIT + drverr_unknown_command)
  1661.         ret
  1662.  
  1663. cdrom_input_flush endp
  1664.  
  1665.  
  1666. ;======================================================================
  1667. ;
  1668. ; DEVICE OPEN command
  1669. ;
  1670. ; Indicates to the device driver that an application is beginning to use it.
  1671. ;
  1672. ;======================================================================
  1673. cdrom_device_open proc near
  1674.  
  1675.         clc
  1676.         ret
  1677.  
  1678. cdrom_device_open endp
  1679.  
  1680.  
  1681. ;======================================================================
  1682. ;
  1683. ; DEVICE CLOSE command
  1684. ;
  1685. ; Indicates to the device driver that an application is beginning to use it.
  1686. ;
  1687. ;======================================================================
  1688. cdrom_device_close proc near
  1689.  
  1690.         clc
  1691.         ret
  1692.  
  1693. cdrom_device_close endp
  1694.  
  1695.  
  1696. ;***************************************************************
  1697. ;
  1698. ; Device dependent helper functions.
  1699. ;
  1700. ;***************************************************************
  1701.  
  1702.  
  1703. ;---------------------------------------------------------------
  1704. ;
  1705. ; cdrom_current_loc
  1706. ;
  1707. ; Return the current location of the drive head as a HSG sector address.
  1708. ; This must be implemented using the Q-channel since the caller must
  1709. ; be able to expect the successful operation of this routine will not
  1710. ; interrupt audio playing.
  1711. ;
  1712. ; Entry:
  1713. ;   bx - drive number
  1714. ;
  1715. ; Exit:
  1716. ;   trashes cx
  1717. ;   Carry set   - an error occurred, ax contains drive status bits
  1718. ;   Carry clear - dx:ax = current HSG logical sector location of drive head.
  1719. ;
  1720. ;---------------------------------------------------------------
  1721. cdrom_current_loc proc near
  1722.  
  1723.         push    bx
  1724.  
  1725.         mov     cs:loc_cnt,800          ;read up to 800 tracks
  1726.  
  1727. loc_status:
  1728.         call    cdrom_drive_status      ;returns with dx = drive number
  1729.         jc      loc_error
  1730.         test    al,40h                  ;open?
  1731.         jnz     loc_error
  1732.         call    status_mode_check
  1733.         jnc     @f
  1734.  
  1735.         mov     ah,STATUS_CMD
  1736.         call    CDREAD
  1737.         jc      loc_error
  1738.         test    al,02h                  ;drive ready?
  1739.         jz      @f                      ;  yes
  1740.                                         
  1741. loc_next:                      
  1742.         dec     cs:loc_cnt              ;  no, not ready, give more time?
  1743.         jnz     loc_status              ;    yes
  1744.                                         ;    no
  1745. loc_error:                              ;read micro-RAM into 'BUF'
  1746.         mov     ah,04h
  1747.         stc
  1748.         jmp     short loc_exit
  1749. @@:
  1750. ;
  1751. ; the drive is ready, read the Q-channel to get the head location
  1752. ;
  1753.         push    es                      ;(10)
  1754.         mov     ax,cs
  1755.         mov     es,ax
  1756.         mov     ax,(READ_Q_CMD shl 8)
  1757.         xor     cx,cx
  1758.         mov     bx,offset cs:BUF
  1759.         call    CDREAD                  ;Get 10 Q-channel bytes
  1760.         pop     es                      ;(9)
  1761.         jc      loc_error
  1762.  
  1763.         mov     al,cs:[bx].ctrl_adr
  1764.         and     al,0Fh
  1765.         cmp     al,1                    ;ADR=1?
  1766.         jne     loc_next       ;  no
  1767.  
  1768.         mov     al,cs:[bx].tno
  1769.         or      al,al                   ;TNO=0?
  1770.         jnz     @f                      ;  no, go calculate frame (sector)
  1771.         cbw                             ;  yep, we're at address 0
  1772.         mov     dx,ax
  1773.         jmp     short loc_exit
  1774. @@:
  1775. ;
  1776. ; calculate the HSG sector address
  1777. ;
  1778.         mov     al,cs:[bx].pmin
  1779.         call    bcd2bin
  1780.         mov     cl,60
  1781.         mul     cl
  1782.         mov     cx,ax                   ;cx = minutes * (60 sec/min)
  1783.         mov     al,cs:[bx].psec
  1784.         call    bcd2bin
  1785.         add     cx,ax                   ;cx += num seconds
  1786.         mov     ax,cx
  1787.         cmp     ax,99*60                ;within 99 minute?
  1788.         jbe     @f                      ;  yes
  1789.         xor     ax,ax                   ;  no, invalid address!
  1790.         mov     dx,ax
  1791.         jmp     short loc_exit
  1792. @@:
  1793.         mov     dx,75
  1794.         mul     dx                      ;total whole seconds *= 75 frames/sec
  1795.         mov     cx,ax
  1796.         mov     al,cs:[bx].pframe
  1797.         call    bcd2bin                 ; += current frame address (0..75)
  1798.         add     ax,cx
  1799.         adc     dx,0                    ;dx:ax = frame number head is now at
  1800.         sub     ax,150                  ;convert to HSG sectors
  1801.         sbb     dx,0                    ;leaves carry clear if no error
  1802.  
  1803. loc_exit:
  1804.         pop     bx
  1805.         ret
  1806.  
  1807. cdrom_current_loc endp
  1808.  
  1809.  
  1810. ;---------------------------------------------------------------
  1811. ;
  1812. ; cdrom_drive_status
  1813. ;
  1814. ; Return status of the drive.  Also flags toc_table as invalid if the
  1815. ; disc has changed or the requested drive is different from last time.
  1816. ;
  1817. ; This routine is used by device independent and device dependent code.
  1818. ;
  1819. ; When called from the device independent get_drive_status in MSCDEX.ASM
  1820. ; the carry flag is expected to indicate whether the drive is ready.
  1821. ;
  1822. ; When called from withing CD.ASM other information may be returned.
  1823. ;
  1824. ; Entry:
  1825. ;       bx - drive num (0 based)
  1826. ;
  1827. ; Exit:
  1828. ;       trashes dx (leaves set to drive number)
  1829. ;       carry set -> drive not ready error
  1830. ;       zero  set -> time out error
  1831. ;       ax        -> 7 6 5 4 3 2 1 0
  1832. ;                    | | | | | | | |
  1833. ;                    | | | | | | |  - time out error
  1834. ;                    | | | | | | |
  1835. ;                    | | | | | |  --- media changed 
  1836. ;                    | | | | | |
  1837. ;                    | | | | |  ----- playing audio   
  1838. ;                    | | | | |
  1839. ;                    | | | |  ------- ?
  1840. ;                    | | | |
  1841. ;                    | | |  --------- ? 
  1842. ;                    | | |
  1843. ;                    | |  ----------- drive door is open   
  1844. ;                    | |
  1845. ;                    |  ------------- ?
  1846. ;                    |
  1847. ;                     --------------- drive not ready error
  1848. ;
  1849. ;---------------------------------------------------------------
  1850. cdrom_drive_status proc near
  1851.  
  1852.         mov     dx,bx
  1853.  
  1854.         mov     ah,DRVSTS_CMD           ;get current drive status
  1855.         call    CDREAD
  1856.         jc      status_not_ready
  1857.         test    al,80h
  1858.         jnz     status_not_ready
  1859.         test    al,(20h or 40h)         ;no error, but disc changed?
  1860.         jz      @f                      ;   no
  1861.         mov     cs:disc_changed[bx],1   ;   yes, set the disc changed flag
  1862.         cmp     dl,cs:toc_drive         ;drive changed?
  1863.         jne     @f                      ;  no
  1864.         mov     cs:toc_drive,0ffh       ;  yes
  1865. @@:
  1866.         or      al,1                    ;clear zero  flag
  1867.         clc                             ;clear carry flag
  1868.         ret
  1869.  
  1870. status_not_ready:
  1871.         cmp     dl,cs:toc_drive         ;drive changed
  1872.         jne     @f
  1873.         mov     cs:toc_drive,0ffh
  1874. @@:
  1875.         cmp     al,10h                  ;if was time out error set zero flag
  1876.         stc                             ;set carry flag
  1877.         ret
  1878.  
  1879. cdrom_drive_status endp
  1880.  
  1881.  
  1882. ;---------------------------------------------------------------
  1883. ;
  1884. ; cdrom_audio_check
  1885. ;
  1886. ; Report whether the drive thinks it's in audio play mode.
  1887. ;
  1888. ; Entry:
  1889. ;       bx - drive number (0 based)
  1890. ;
  1891. ; Exit:
  1892. ;       carry set   -     in audio play mode
  1893. ;       carry clear - not in audio play mode
  1894. ;
  1895. ;---------------------------------------------------------------
  1896. cdrom_audio_check proc near
  1897.  
  1898.         call    cdrom_drive_status
  1899.         jc      @f                      ;error occurred?
  1900.         and     al,1Ch                  ;  no, does the drive think..
  1901.         cmp     al,04h                  ;  ..it is playing audio?
  1902.         jne     @f                      ;      nope
  1903.         stc                             ;      yep
  1904.         ret
  1905. @@:     clc
  1906.         ret
  1907.  
  1908. cdrom_audio_check endp
  1909.  
  1910.  
  1911. ;***************************************************************
  1912. ;
  1913. ; Various private helper functions.
  1914. ;
  1915. ;***************************************************************
  1916.  
  1917. ;---------------------------------------------------------------
  1918. ;
  1919. ; status_mode_check
  1920. ;
  1921. ; Ancillary routine to check_device_status().  Further isolates the
  1922. ; drive status bits to return carry clear when the drive is in a
  1923. ; valid state.
  1924. ;
  1925. ;---------------------------------------------------------------
  1926. status_mode_check proc near
  1927.  
  1928.         and     al,1Ch                  ;mask not 'MODE' bits
  1929.         cmp     al,08h                  ;stop/read/play/pause valid mode?
  1930.         jbe     @f                      ;  yes
  1931.         stc                             ;  no
  1932.         ret
  1933. @@:
  1934.         clc
  1935.         ret
  1936.  
  1937. status_mode_check endp
  1938.  
  1939.  
  1940. ifdef DEBUG
  1941. ;----------------------------------------------------------------------
  1942. ;
  1943. ; Various routines to remain resident in driver when debugging.
  1944. ;
  1945. ;----------------------------------------------------------------------
  1946.  
  1947.  
  1948.  
  1949.  
  1950.  
  1951.  
  1952. failure         db      '$failed',0
  1953. media_chgd      db      '$media_changed',0
  1954.  
  1955. ;----------------------------------------------------------------------
  1956. ;
  1957. ; disp_char_resident
  1958. ;
  1959. ; Displays the passed character on the console
  1960. ;
  1961. ; Entry:
  1962. ;    al - hex character to display.
  1963. ;
  1964. ;----------------------------------------------------------------------
  1965. disp_char_resident proc near
  1966.  
  1967.         push    bx      ;(1)            ;Save (BX)
  1968.         push    cx      ;(2)            ;Save (CX)
  1969.         push    dx      ;(3)            ;Save (DX)
  1970.  
  1971.         mov     ah,9                    ;write char
  1972.         mov     bx,70h                  ;Reverse video
  1973.         mov     cx,1
  1974.         int     10h                     ;IBM PC/BIOS video int. call
  1975.  
  1976.         mov     ah,3                    ;read cursor pos.
  1977.         mov     bh,0
  1978.         int     10h
  1979.         inc     dl                      ;Bump column by 1
  1980.         cmp     dl,80                   ;Past end-of-line ??
  1981.         jc      same_line               ; no
  1982.                                         ; yes
  1983.         mov     dl,0                    ;Cursor to start of line
  1984.         inc     dh
  1985.         cmp     dh,25                   ;Past end-of-screen ??
  1986.         jc      same_line               ; no
  1987.                                         ; yes
  1988.         mov     dh,24                   ;Move back to the last line
  1989.         push    dx      ;(4)            ;Save (cursor pos.)
  1990.         mov     ax,0601h                ;Scroll up one line
  1991.         mov     cx,0000h                ;ULcorner of screen
  1992.         mov     dx,184fh                ;LRcorner of screen
  1993.         int     10h
  1994.         pop     dx      ;(3)            ;Restore (cursor pos.)
  1995. same_line:
  1996.         mov     ah,2                    ;set cursor pos.
  1997.         int     10h
  1998.  
  1999.         pop     dx      ;(2)            ;Restore (DX)
  2000.         pop     cx      ;(1)            ;Restore (CX)
  2001.         pop     bx      ;(0)            ;Restore (BX)
  2002.         ret
  2003.  
  2004. disp_char_resident endp
  2005.  
  2006.  
  2007. ;----------------------------------------------------------------------
  2008. ;
  2009. ; disp_msg
  2010. ;
  2011. ;----------------------------------------------------------------------
  2012.     public disp_msg
  2013. disp_msg proc near
  2014.  
  2015. next_char:
  2016.         mov     al,cs:[si]              ;(AL) = *(SI)++
  2017.         inc     si
  2018.         and     al,al                   ;End-of-message ??
  2019.         je      exit_disp_msg           ; yes
  2020.                                         ; no
  2021.         call    disp_char_resident      ;Display the character
  2022.         jmp     short next_char
  2023. exit_disp_msg:
  2024.         ret
  2025.  
  2026. disp_msg endp
  2027.  
  2028.  
  2029. ;----------------------------------------------------------------------
  2030. ;
  2031. ; disp_hex_nibble
  2032. ;
  2033. ;----------------------------------------------------------------------
  2034. disp_hex_nibble proc near
  2035.  
  2036.         add     al,'0'                  ;Add-in the "numeric" ASCII bias
  2037.         cmp     al,'9' + 1              ;Greater than 9 ??
  2038.         jc      lt9                     ; no
  2039.                                         ; yes
  2040.         add     al,'a' - ('9' + 1)      ;Convert to "alphabetic" ASCII
  2041. lt9:
  2042.         call    disp_char_resident      ;Display char. in (AL)
  2043.         ret
  2044.  
  2045. disp_hex_nibble endp
  2046.  
  2047.  
  2048. ;----------------------------------------------------------------------
  2049. ;
  2050. ; disp_hex_byte
  2051. ;
  2052. ;----------------------------------------------------------------------
  2053.     public disp_hex_byte
  2054.  
  2055. disp_hex_byte proc near
  2056.  
  2057.         push    ax      ;(1)            ;save (AX)
  2058.         push    ax      ;(2)            ;save (lshexdigit of byte)
  2059.         shr     al,1
  2060.         shr     al,1
  2061.         shr     al,1
  2062.         shr     al,1                    ;(AL) = mshexdigit
  2063.         call    disp_hex_nibble         ;Display hex nibble in (AL)
  2064.  
  2065.         pop     ax      ;(1)            ;restore (lshexdigit of byte)
  2066.         and     al,0fh                  ;(AL) = lshexdigit
  2067.         call    disp_hex_nibble         ;Display hex nible in (AL)
  2068.  
  2069.         pop     ax      ;(0)            ;restore (AX)
  2070.         ret
  2071.  
  2072. disp_hex_byte endp
  2073.  
  2074.  
  2075. endif   ;DEBUG
  2076.  
  2077.  
  2078. _TEXT   ends
  2079.  
  2080.  
  2081.  
  2082. _LAST   segment para public 'last'
  2083.         assume  cs:_LAST
  2084.  
  2085.  
  2086. ifdef DEBUG
  2087.  
  2088. ;----------------------------------------------------------------------
  2089. ; disp_char_inittime
  2090. ;
  2091. ; Output a character to the console for debugging purposes.
  2092. ;
  2093. ; Entry:
  2094. ;   al contains character to output.
  2095. ;----------------------------------------------------------------------
  2096.  
  2097. disp_char_inittime proc near
  2098.  
  2099.         push    bx      ;(1)            ;Save (BX)
  2100.         push    cx      ;(2)            ;Save (CX)
  2101.         push    dx      ;(3)            ;Save (DX)
  2102.  
  2103.         mov     ah,9                    ;write char
  2104.         mov     bx,70h                  ;Reverse video
  2105.         mov     cx,1
  2106.         int     10h                     ;IBM PC/BIOS video int. call
  2107.  
  2108.         mov     ah,3                    ;read cursor pos.
  2109.         mov     bh,0
  2110.         int     10h
  2111.         inc     dl                      ;Bump column by 1
  2112.         cmp     dl,80                   ;Past end-of-line ??
  2113.         jc      same_line_s             ; no
  2114.                                         ; yes
  2115.         mov     dl,0                    ;Cursor to start of line
  2116.         inc     dh
  2117.         cmp     dh,25                   ;Past end-of-screen ??
  2118.         jc      same_line_s             ; no
  2119.                                         ; yes
  2120.         mov     dh,24                   ;Move back to the last line
  2121.         push    dx      ;(4)            ;Save (cursor pos.)
  2122.         mov     ax,0601h                ;Scroll up one line
  2123.         mov     cx,0000h                ;ULcorner of screen
  2124.         mov     dx,184fh                ;LRcorner of screen
  2125.         int     10h
  2126.         pop     dx      ;(3)            ;Restore (cursor pos.)
  2127. same_line_s:
  2128.         mov     ah,2                    ;set cursor pos.
  2129.         int     10h
  2130.  
  2131.         pop     dx      ;(2)            ;Restore (DX)
  2132.         pop     cx      ;(1)            ;Restore (CX)
  2133.         pop     bx      ;(0)            ;Restore (BX)
  2134.         ret
  2135.  
  2136. disp_char_inittime endp
  2137.  
  2138. endif   ;DEBUG
  2139.  
  2140. ;
  2141. ; init data variables
  2142. ;
  2143.  
  2144. msg             db      0dh,0ah,0dh,0ah
  2145. ifdef DEBUG
  2146.                 db      '*** Hitachi CD-ROM device driver, DEBUG version 2.2 ***'
  2147. else
  2148.                 db      '*** Hitachi CD-ROM device driver, version 2.2 ***'
  2149. endif
  2150.                 db      0dh,0ah,'  (C)Copyright Hitachi, LTD. 1987-1990.'
  2151.                 db      0dh,0ah,'  Device Name        : ',0
  2152. msg2            db      ' ',0
  2153. msg3            db      0dh,0ah,'  Number of drives   : ',0
  2154. msg4            db      0dh,0ah,0dh,0ah,0
  2155. errmsg1         db      0dh,0ah,'  Invalid /p switch  : ',0
  2156. errmsg2         db      0dh,0ah,'  Drive not ready, aborting installation',0dh,0ah,0
  2157.  
  2158. devname_len     dw      8
  2159. devname_bufr    db      '12345678'
  2160.  
  2161. CHK_IF_WORK DB  ?
  2162. TIMER_MICRO DW  0
  2163. TIMER_MILLI DW  0
  2164. TIMER_CONVERT   DW      8381    ;838.095 ns/tick
  2165. COUNT_CONVERT   DW      54925   ;54.925 ms/count
  2166. TEN_THOUSAND    DW      10000
  2167. THOUSAND        DW      1000
  2168. OK_COUNT        DB      0
  2169.  
  2170.  
  2171. ;============================================================
  2172. ;
  2173. ; INIT command
  2174. ;
  2175. ; This is the initialization requested from DOS in loading the device driver
  2176. ; from the CONFIG.SYS file.
  2177. ;
  2178. ; Entry:
  2179. ;   ds:bx - far ptr to the request header
  2180. ;       InitHeader    struc
  2181. ;
  2182. ;       init_rqh        db  size Request_Hdr dup (?)
  2183. ;       init_units      db  ?
  2184. ;       init_endaddr    dd  ?
  2185. ;       init_bpbarr     dd  ?
  2186. ;       init_devno      db  ?
  2187. ;       InitHeader    ends
  2188. ;
  2189. ;============================================================
  2190. cdrom_init proc near
  2191.  
  2192. ;
  2193. ; Simple minded command line scanner
  2194. ;
  2195.         push    es
  2196.         push    ds
  2197.  
  2198.         assume  es:_TEXT
  2199.         mov     ax,_TEXT
  2200.  
  2201.         mov     es,ax
  2202.  
  2203.         lds     si,ds:init_bpbarr[bx]   ;get ptr to command line
  2204. sloop:
  2205.         lodsb                           ;Scan for switch on command line
  2206.         cmp     al,0Dh
  2207.         je      cmd_done
  2208.         cmp     al,0Ah
  2209.         je      cmd_done
  2210.         cmp     al,'/'
  2211.         je      switch
  2212.  
  2213.         jmp     short sloop
  2214. cmd_done:
  2215.         jmp     nomore
  2216. ;
  2217. ; See what switch is being specified
  2218. ;
  2219. switch:
  2220.         mov     al,[si]
  2221.         or      al,20h                  ;lower case
  2222.         cmp     al,'c'                  ; /c - set minutes for power save
  2223.         jne     switch_1
  2224.         jmp     sw6
  2225. switch_1:
  2226.         cmp     byte ptr [si+1],':' ;Go on if letter not followed by a ':'
  2227.         jne     sloop
  2228.  
  2229.         cmp     al,'d'                  ; /d - name of device driver
  2230.         je      sw2
  2231.         cmp     al,'n'                  ; /n - number of subunits
  2232.         je      sw3
  2233.         cmp     al,'p'                  ; /p - set I/O port address
  2234.         je      sw5
  2235.         jmp     short sloop
  2236.  
  2237. ;
  2238. ; Copy command line name into device header
  2239. ;
  2240. sw2:
  2241.         add     si,2
  2242.         mov     cx,8
  2243.         mov     di,offset DeviceHeader+10
  2244. swloop:
  2245.         lodsb                           ;copy to ' ', CR, or LF
  2246.         cmp     al,' '
  2247.         je      finish
  2248.         cmp     al,0dh
  2249.         je      finish
  2250.         cmp     al,0ah
  2251.         je      finish
  2252.         cmp     al,09h                  ;TAB
  2253.         je      finish
  2254.  
  2255.  
  2256.         stosb                           ;offset
  2257.         loop    swloop
  2258. finish:
  2259.         dec     si                      ;(Backup so sloop sees terminator)
  2260.         push    cx      ;(10)           ;save cx
  2261.         cmp     cx,0
  2262.         je      nopad
  2263.         mov     al,' '                  ;pad with blanks
  2264. wrap_up:
  2265.         stosb                           ;CX has count of blanks
  2266.         loop    wrap_up
  2267. nopad:
  2268.         pop     ax      ;(9)            ;restore ax (value WAS in cx)
  2269.         mov     cx,8
  2270.         sub     cx,ax                   ;(CX) = # of chars in device name
  2271.         cmp     cx,0
  2272.         jne     nopad_1
  2273.         mov     cx,8
  2274. nopad_1:
  2275.         mov     cs:devname_len,cx       ;Save the length of the device name
  2276.  
  2277.         jmp     short sloop             ;Look for more (other) switches
  2278. sw3:
  2279.         add     si,2                    ;skip over the 'n:'
  2280.         lodsb                           ;Get the digit following /n:
  2281.  
  2282.         cmp     al,'1'                  ;Make sure numdrives is ok (1-4)
  2283.         jc      sloop                   ; too small, look for more switches
  2284.         cmp     al,'8'+1
  2285.         jnc     sloop                   ; too large, look for more switches
  2286.  
  2287.         sub     al,'0'                  ;Subtract out the ASCII bias
  2288.         mov     es:units,al             ;Setup the number of sub-units
  2289.  
  2290. goon:
  2291.         jmp     sloop                   ;Look for more (other) switches
  2292. sw5:
  2293.         add     si,2                    ;skip over the 'p:'
  2294.         call    next_hex_digit          ;Get the 1st hex digit after /p:
  2295.         jc      goon                    ;Abort if 1st hex digit was bad!
  2296.  
  2297.         mov     dl,al                   ;(DX) = hex. value
  2298.         mov     dh,0
  2299. sw5_nextdig:
  2300.         call    next_hex_digit          ;Get the 2nd hex digit after /p:
  2301.         jc      sw5_sport               ;Jump if last digit reached
  2302.  
  2303.         mov     cl,4                    ;Shift prev. hex digit up 4 bits
  2304.         shl     dx,cl
  2305.         or      dl,al                   ;Or in lshexdigit
  2306.  
  2307.         jmp     short sw5_nextdig
  2308. sw5_sport:
  2309.         cmp     dx,300h                 ;default i/o port addres??
  2310.         jne     sw5_chk                 ;  no
  2311.         dec     si                      ;  yes
  2312.         jmp     goon
  2313. sw5_chk:
  2314.  
  2315.         IRP     DUMMY,<200h,220h,240h,260h,320h,340h,360h>
  2316.         cmp     dx,DUMMY                ;supported i/o address??
  2317.         je      sw5_sport2              ; yes
  2318.         ENDM
  2319.  
  2320.         jmp     goon                    ;not supported i/o port address
  2321.  
  2322. sw5_sport2:
  2323.         dec     si                      ;(Backup so sloop sees terminator)
  2324.  
  2325.         mov     cx,dx
  2326.         mov     dx,0                    ;should be dl=0
  2327.         mov     ah,MODESET_CMD
  2328.         mov     al,2                    ;setup based i/o port address
  2329.         call    CDREAD
  2330.         jc      sw5_err
  2331.         jmp     goon
  2332. sw5_err:
  2333.         mov     cx,-1
  2334.         mov     di,offset errmsg1
  2335.         call    outstr
  2336.         jmp     goon
  2337.  
  2338. ;
  2339. ; set the number of minutes for the power save option (or disable it)
  2340. ;
  2341. sw6:
  2342.  
  2343. ifdef DEBUG
  2344.         call    disp_char_inittime
  2345. endif
  2346.         xor     dx,dx                   ;dl = minutes before spin down
  2347.         inc     si
  2348.         cmp     byte ptr cs:[si],':'    ;setting number of minutes?
  2349.         je      @f                      ;  yes, get how many minutes (0-14h)
  2350.         jmp     short sw6_got_pwr_save  ;  nope, disabling power down feature
  2351. @@:     inc     si
  2352.         call    next_hex_digit
  2353.         jc      sw6_got_pwr_save        ;1st char was not valid hex?
  2354.         mov     dl,al                   ;  nope, was OK
  2355.         call    next_hex_digit
  2356.         jc      sw6_got_pwr_save        ;was only one hex digit?
  2357.         mov     cl,4                    ;  nope, were two digits
  2358.         shl     dl,cl
  2359. sw6_got_pwr_save:
  2360.         mov     es:pwr_save,dl
  2361.         jmp     goon
  2362.  
  2363. nomore:
  2364.         mov     cx,cs:devname_len
  2365.         mov     si,offset DeviceHeader+10
  2366.         mov     di,offset devname_bufr
  2367. copydev:
  2368.         mov     al,es:[si]
  2369.         mov     cs:[di],al
  2370.         inc     si
  2371.         inc     di
  2372.         loop    copydev
  2373.  
  2374.         mov     cx,-1                   ;(CX) = -1 (nul-terminated string)
  2375.         mov     di,offset msg
  2376.         call    outstr
  2377.  
  2378.         mov     cx,cs:devname_len
  2379.         mov     di,offset devname_bufr
  2380.         call    outstr
  2381.  
  2382.         mov     dl,es:units             ;Setup the number of sub-units
  2383.         dec     dl
  2384.  
  2385. ifdef DEBUG
  2386.         push    ax
  2387.         mov     al,dl
  2388.         add     al,'0'
  2389.         call    disp_char_inittime
  2390.         pop     ax
  2391. endif
  2392.  
  2393.         cmp     dl,4
  2394.         jb      drive_ok
  2395.         mov     ah,13h                  ;bad command
  2396.         call    CDREAD
  2397.         jnc     drive_ok
  2398.  
  2399. ifdef DEBUG
  2400.         push    ax
  2401.         mov     al,ah
  2402.         add     al,'0'
  2403.         call    disp_char_inittime
  2404.         pop     ax
  2405. endif
  2406.  
  2407.         cmp     ah,02h                  ;bad parameter
  2408.         jne     drive_ok
  2409.         mov     es:units,1              ;bad parameter
  2410.                                         ;support only 4 units
  2411. drive_ok:
  2412.         mov     al,es:pwr_save
  2413.  
  2414. ifdef DEBUG
  2415.         add     al,'0'
  2416.         call    disp_char_inittime
  2417.         mov     al,es:pwr_save
  2418. endif
  2419.  
  2420.         mov     cl,es:units
  2421.         xor     ch,ch
  2422. pwr_loop:
  2423.         push    cx
  2424.         push    ax
  2425.         mov     ah,SET_POWER_SAVE
  2426.         mov     dl,cl
  2427.         dec     dl
  2428.         call    CDREAD
  2429.         pop     ax
  2430.         pop     cx
  2431.         loop    pwr_loop
  2432. ;
  2433. ; Initialize timing variables
  2434. ; if successful fill in the driver's end address
  2435. ; else fail the init
  2436. ;
  2437.         push    bx
  2438.         call    init_timer_variables    ;returns carry clear if successful
  2439.         pop     bx                      ;restore request header offset
  2440.         pop     ds
  2441.         mov     ax,offset _LAST:very_end
  2442.         mov     dx,seg _LAST
  2443.         jnc     @f                      ;error in init?
  2444.         mov     cx,-1                   ;  yes, print error message...
  2445.         mov     di,offset errmsg2
  2446.         call    outstr
  2447.         xor     ax,ax                   ;...return 0 offset...
  2448.         mov     dx,seg _TEXT            ;...from DeviceHeader's segment
  2449.         and     es:DeviceHeader+2,7fffh ;...and look like a block device
  2450.         stc                             ;skip msg3
  2451. @@:
  2452.         mov     word ptr ds:init_endaddr[bx].lo,ax
  2453.         mov     word ptr ds:init_endaddr[bx].hi,dx
  2454.         mov     byte ptr ds:init_units[bx],0
  2455.         mov     byte ptr ds:init_devno[bx],0
  2456.         jc      @f                      ;skip msg3?
  2457.  
  2458.         mov     cx,-1                   ;  no, must have init'd OK
  2459.         mov     di,offset msg3
  2460.         call    outstr
  2461.         mov     dl,es:units
  2462.         add     dl,'0'
  2463.         mov     ah,02h
  2464.         int     21h
  2465. @@:
  2466.         mov     cx,-1
  2467.         mov     di,offset msg4
  2468.         call    outstr
  2469.  
  2470.         assume  es:nothing
  2471.         pop     es
  2472.         ret
  2473.  
  2474. cdrom_init endp
  2475.  
  2476.  
  2477. ;----------------------------------------------------------------------
  2478. ; outstr
  2479. ;
  2480. ; Output a string to stdout
  2481. ;
  2482. ; Entry:
  2483. ;    cs:di - points to string
  2484. ;       cx - contains string length (if not null terminated)
  2485. ;
  2486. ; Exit
  2487. ;----------------------------------------------------------------------
  2488. outstr  proc    near
  2489.  
  2490.         push    ax      ;(1)            ;save (AX)
  2491.         push    dx      ;(2)            ;save (DX)
  2492. oloop:
  2493.         mov     dl,cs:[di]
  2494.         inc     di
  2495.  
  2496.         and     dl,dl                   ;Reached null termination ??
  2497.         jz      done                    ; yes
  2498.                                         ; no
  2499.         mov     ah,02h                  ;write char to STO
  2500.         int     21h
  2501.  
  2502.         loop    oloop                   ;Loop until (CX) = 0 or null
  2503. done:
  2504.         pop     dx      ;(1)            ;restore (DX)
  2505.         pop     ax      ;(0)            ;restore (AX)
  2506.  
  2507.         ret
  2508.  
  2509. outstr  endp
  2510.  
  2511.  
  2512. ;----------------------------------------------------------------------
  2513. ;
  2514. ; next_hex_digit
  2515. ;
  2516. ; Return the next hex digit on the command line
  2517. ;
  2518. ;----------------------------------------------------------------------
  2519. next_hex_digit proc near
  2520.  
  2521.         lodsb                           ;Get the next byte from cmd line
  2522.         cmp     al,'0'                  ;Numeric digit ??
  2523.         jc      not_hdig                ; no
  2524.                                         ; maybe
  2525.         cmp     al,'9'+1                ;Numeric digit ??
  2526.         jc      is_numdig               ; yes
  2527.                                         ; no
  2528.         cmp     al,'A'                  ;(A-F) digit ??
  2529.         jc      not_hdig                ; no
  2530.                                         ; maybe
  2531.         cmp     al,'F'+1                ;(A-F) digit ??
  2532.         jc      is_uafdig               ; yes
  2533.                                         ; no
  2534.         cmp     al,'a'                  ;(a-f) digit ??
  2535.         jc      not_hdig                ; no
  2536.                                         ; maybe
  2537.         cmp     al,'f'+1                ;(a-f) digit ??
  2538.         jnc     not_hdig                ; no
  2539.                                         ; yes
  2540.         sub     al,('a'-10)             ;Convert to hex. value
  2541. is_hdig:
  2542.         clc                             ;Clear carry & return
  2543.         ret                             ;(hex. value in AL)
  2544. is_uafdig:
  2545.         sub     al,('A'-10)             ;Convert to hex. value
  2546.         jmp     short is_hdig
  2547. is_numdig:
  2548.         sub     al,'0'                  ;Conver to hex. value
  2549.         jmp     short is_hdig
  2550. not_hdig:
  2551.         stc                             ;Set carry & return
  2552.         ret                             ;(ASCII char. in AL)
  2553.  
  2554. next_hex_digit endp
  2555.  
  2556.  
  2557. ;---------------------------------------------
  2558. ; Timer variable initialization
  2559. ;
  2560. ; This was located in CDREAD() and done on the first READ call,
  2561. ; now it's done when the driver is installed.
  2562. ;
  2563. ; (You don't want to look at this stuff if you don't have to!!!)
  2564. ;
  2565. ; Entry:
  2566. ;       es - _TEXT
  2567. ;
  2568. ; Register usage:
  2569. ;       cs - _LAST (use cs override for _LAST variables)
  2570. ;       ds - _TEXT
  2571. ;       es - _TEXT
  2572. ;
  2573. ; Exit:
  2574. ;       carry clear - successful init
  2575. ;       carry set   - drive not ready error (probably turned off)
  2576. ;---------------------------------------------
  2577. init_timer_variables proc near
  2578.  
  2579.         mov     ax,_TEXT
  2580.         mov     ds,ax
  2581.  
  2582.         MOV     BP,WORD PTR CURRENT_IF
  2583.         INC     BP                        ;POINT AT PPI_PB
  2584.  
  2585.         CALL    CPU_CHK                 ;CHECK CPU type
  2586.         CALL    CHK_IF                  ;returns zero set if error
  2587.         jnz     @f
  2588.         stc                             ;carry set for init error
  2589.         ret
  2590. @@:
  2591.         CMP     CPU_MODE,2
  2592.         JNZ     @f
  2593.         CALL    CLOCK_CALC          ;80286
  2594.         JNC     done_timer_init
  2595.         CALL    CLOCK_CALC
  2596.         JMP     SHORT done_timer_init
  2597. @@:                             ;8088
  2598.         CALL    CLOCK_CALC_88
  2599.         JNC     done_timer_init
  2600.         CALL    CLOCK_CALC_88
  2601. done_timer_init:
  2602.         clc                             ;carry clear for successful init
  2603.         ret
  2604.  
  2605. init_timer_variables endp
  2606.  
  2607.  
  2608.  
  2609. CPU_CHK PROC    NEAR
  2610.         XOR     BL,BL
  2611.         MOV     AX,4
  2612.         MOV     CL,20H
  2613.         SHR     AX,CL
  2614.         TEST    AX,4
  2615.         JZ      CPU_CHK_END
  2616.         PUSH    SP
  2617.         POP     AX
  2618.         CMP     AX,SP
  2619.         JNZ     CPU_CHK_END
  2620.         MOV     BL,2        ;80286 MODE
  2621. CPU_CHK_END:
  2622.         MOV     CPU_MODE,BL
  2623.         RET
  2624. CPU_CHK ENDP
  2625.  
  2626.  
  2627.  
  2628. CHK_IF      PROC    NEAR            ; CHECK IF CARD
  2629. CHK_IF_LOOP_1:
  2630.         MOV     TWICE,2
  2631. CHK_IF_LOOP_2:
  2632.         MOV     ERRCNT,RETRY2
  2633.         MOV     CS:CHK_IF_WORK,AH
  2634.         DEC     TWICE
  2635. CHK_IF_1:
  2636.         MOV     IF_FLAG,1
  2637.         CALL    _STATUS_COMMAND     ;ISSUE STATUS COMMAND
  2638.         MOV     IF_FLAG,0
  2639.         JNZ     CHK_IF_0
  2640.         DEC     ERRCNT                 ;RETRY
  2641.         JNZ     CHK_IF_1
  2642.         RET
  2643. CHK_IF_0:
  2644.         XOR     AH,AH
  2645.         MOV     AL,BYTE PTR STA_CODE   ;SET STATUS CODE IN AL
  2646.         CMP     AL,0FFH
  2647.         JNE     CHK_IF_TWICE           ;SUPPORT SOFT TRNS
  2648.         INC     AH                     ;NOT SUPPRORT SOFT TRNS
  2649. CHK_IF_TWICE:
  2650.         CMP     TWICE,0
  2651.         JNE     CHK_IF_LOOP_2           ;2nd CHECK
  2652. CHK_IF_2:
  2653.         CMP     AH,CS:CHK_IF_WORK
  2654.         JNE     CHK_IF_LOOP_1       ;TRY AGAIN
  2655. CHK_IF_3:
  2656.         MOV     BYTE PTR CURRENT_IF_MODE,AH
  2657.         OR      AH,80H
  2658.         RET
  2659. CHK_IF      ENDP
  2660.  
  2661.  
  2662. CLOCK_CALC  PROC    NEAR
  2663.         XOR     AL,AL
  2664.         MOV     CLOCK_COUNT,AL
  2665.         CALL    INSB_INIT
  2666. TIMER_LOOP_0:
  2667.         MOV     CS:OK_COUNT,2
  2668. TIMER_LOOP_1:
  2669.         MOV     CX,1000
  2670.         LEA     DI,_TEXT:BUF
  2671.         CALL    TIMER_START     
  2672.         CALL    _INSB_LOOP_ENT          ; far entry point
  2673.         CALL    TIMER_STOP
  2674. ;
  2675.         CALL    TIMER_CHK
  2676.         JZ      LOW_CLOCK           ;TOO LOW CLOCK
  2677.         JB      NEXT_LOOP               ; YET HIGH
  2678.         DEC     CS:OK_COUNT
  2679.         JNZ     TIMER_LOOP_1
  2680. OK_END:
  2681.         MOV     CLOCK_MODE,0
  2682.         CALL    TIMER_RESTORE
  2683.         CLC
  2684.         RET
  2685.  
  2686. INSB_INIT proc near
  2687.         LEA     DI,_TEXT:INSB_LOOP
  2688.         MOV     AX,0E26CH       ;INSB ,LOOP
  2689.         STOSW                           ;es -> _TEXT
  2690.         MOV     AX,0C3FDH           ;RET
  2691.         STOSW
  2692.         RET
  2693. INSB_INIT endp
  2694.  
  2695.  
  2696. HIGH_CLOCK:
  2697. LOW_CLOCK:
  2698. BAD_END:
  2699.         MOV     CLOCK_MODE,80H
  2700.         CALL    TIMER_RESTORE
  2701.         STC
  2702.         RET
  2703. ;
  2704. NEXT_LOOP:
  2705.         INC     CLOCK_COUNT
  2706.         CMP     CLOCK_COUNT,100
  2707.         JNB     HIGH_CLOCK              ;TOO HIGH CLOCK
  2708. ;
  2709. SUB_1:
  2710.         MOV     CL,CLOCK_COUNT
  2711.         XOR     CH,CH
  2712.         LEA     DI,_TEXT:INSB_LOOP
  2713.         INC     DI
  2714.         MOV     AL,90H              ;NOP
  2715.         REP     STOSB
  2716.         MOV     AL,0E2H             ;LOOP
  2717.         STOSB
  2718.         MOV     AL,0FDH
  2719.         SUB     AL,CLOCK_COUNT
  2720.         STOSB
  2721.         MOV     AL,0C3H         ;----- added 4/2
  2722.         STOSB                   ;----- added 4/2
  2723.         JMP     TIMER_LOOP_0
  2724. ;
  2725. TIMER_CHK:
  2726.         CMP     CS:TIMER_MILLI,5
  2727.         JAE     LOW_NEXT            ;TOO SLOW
  2728.         CMP     CS:TIMER_MILLI,3
  2729.         JA      CHK_NEXT
  2730.         JB      HIGH_NEXT
  2731.         CMP     CS:TIMER_MICRO,700
  2732.         JBE     HIGH_NEXT
  2733. CHK_OK:
  2734.         OR      AX,1
  2735.         CLC
  2736.         RET
  2737. HIGH_NEXT:
  2738.         OR      AL,1
  2739.         STC
  2740.         RET
  2741. CHK_NEXT:
  2742.         CMP     CS:TIMER_MICRO,999
  2743.         JB      CHK_OK
  2744. LOW_NEXT:
  2745.         XOR     AL,AL
  2746.         RET
  2747. ;
  2748. TIMER_RESTORE:
  2749.         CLI
  2750.         PUSH    AX
  2751.         MOV     AL,00110110B            ;CNT 0,LSB then MSB, MODE 2, BINARY
  2752.         OUT     TIMER_MODE,AL
  2753.         JMP     SHORT $+2
  2754.         SUB     AX,AX
  2755.         OUT     TIMER0,AL
  2756.         JMP     SHORT $+2
  2757.         OUT     TIMER0,AL
  2758.         POP     AX
  2759.         STI
  2760.         RET
  2761. ;
  2762. CLOCK_CALC  ENDP
  2763. ;------------------------------------------------------------------
  2764. CLOCK_CALC_88   PROC    NEAR
  2765.         MOV     AX,CS
  2766.         MOV     ES,AX
  2767.         XOR     AL,AL
  2768.         MOV     CLOCK_COUNT,AL
  2769.         CALL    INSB_INIT_88
  2770. CALC_88_LOOP_0:
  2771.         MOV     CS:OK_COUNT,2
  2772. CALC_88_LOOP_1:
  2773.         MOV     CX,31
  2774.         CMP     CLOCK_COUNT,1
  2775.         JBE     CALC_88_LOOP_3
  2776.         MOV     CX,62
  2777.         CMP     CLOCK_COUNT,3
  2778.         JBE     CALC_88_LOOP_3
  2779.         MOV     CX,1000
  2780. CALC_88_LOOP_3:
  2781.         LEA     DI,_TEXT:BUF
  2782.         CALL    TIMER_START
  2783.         CALL    _INSB_LOOP_ENT          ;far entry point
  2784.         CALL    TIMER_STOP
  2785.  
  2786.         CALL    TIMER_CHK
  2787.         JZ      LOW_CLOCK_88            ;TOO LOW CLOCK
  2788.         JB      NEXT_LOOP_88            ; YET HIGH
  2789.         DEC     CS:OK_COUNT
  2790.         JNZ     CALC_88_LOOP_1
  2791. OK_END_88:
  2792.         MOV     CLOCK_MODE,0
  2793.         CALL    TIMER_RESTORE
  2794.         CLC
  2795.         RET
  2796.  
  2797. HIGH_CLOCK_88:
  2798. LOW_CLOCK_88:
  2799. BAD_END_88:
  2800.         MOV     CLOCK_MODE,80H
  2801.         CALL    TIMER_RESTORE
  2802.         STC
  2803.         RET
  2804. ;
  2805. NEXT_LOOP_88:
  2806.         MOV     CX,32
  2807.         INC     CLOCK_COUNT
  2808.         CMP     CLOCK_COUNT,1
  2809.         JE      NOP_1
  2810.         SHR     CX,1            ;16
  2811.         CMP     CLOCK_COUNT,3
  2812.         JBE     NOP_23
  2813.         CMP     CLOCK_COUNT,100
  2814.         JNB     HIGH_CLOCK_88           ;TOO HIGH CLOCK
  2815. ;
  2816. SUB_1_88:
  2817.         MOV     CL,CLOCK_COUNT
  2818.         SUB     CL,4
  2819.         XOR     CH,CH
  2820.         LEA     DI,_TEXT:INSB_LOOP
  2821.         INC     DI
  2822.         INC     DI
  2823.         CMP     CX,0
  2824.         JE      SUB_1_88_1
  2825.         MOV     AL,90H              ;NOP
  2826.         REP     STOSB
  2827. SUB_1_88_1:
  2828.         MOV     AL,0E2H             ;LOOP
  2829.         STOSB
  2830.         MOV     AL,00H
  2831.         SUB     AL,CLOCK_COUNT
  2832.         STOSB
  2833.         MOV     AL,0C3H
  2834.         STOSB
  2835.         JMP     CALC_88_LOOP_0
  2836. NOP_1:
  2837.         LEA     DI,INSB_LOOP
  2838.         MOV     AX,0AAECH           ;IN AL,DX  STOSB
  2839.         MOV     BL,90H              ;NOP
  2840. NOP_1_1:
  2841.         STOSW
  2842.         XCHG    AL,BL
  2843.         STOSB
  2844.         XCHG    AL,BL
  2845.         LOOP    NOP_1_1
  2846.         MOV     AL,0E2H
  2847.         STOSB
  2848.         MOV     AL,09EH
  2849.         STOSB
  2850.         MOV     AL,0C3H
  2851.         STOSB
  2852.         JMP     CALC_88_LOOP_0
  2853. NOP_23:
  2854.         MOV     AX,0AAECH           ;IN AL,DX  STOSB
  2855.         MOV     BX,9090H            ;NOP NOP
  2856.         LEA     DI,_TEXT:INSB_LOOP
  2857. NOP_23_1:
  2858.         STOSW
  2859.         XCHG    AX,BX
  2860.         STOSW
  2861.         CMP     CLOCK_COUNT,2
  2862.         JE      NOP_23_2
  2863.         STOSB
  2864. NOP_23_2:
  2865.         XCHG    AX,BX
  2866.         LOOP    NOP_23_1
  2867.         MOV     AL,0E2H
  2868.         STOSB
  2869.         MOV     AL,0BEH
  2870.         CMP     CLOCK_COUNT,2
  2871.         JE      NOP_23_3
  2872.         SUB     AL,10H
  2873. NOP_23_3:
  2874.         STOSB
  2875.         MOV     AL,0C3H
  2876.         STOSB
  2877.         JMP     CALC_88_LOOP_0
  2878. ;
  2879. INSB_INIT_88:
  2880.         LEA     DI,_TEXT:INSB_LOOP
  2881.         MOV     CX,32
  2882.         MOV     AX,0AAECH           ;IN AL,DX   STOSB
  2883.         REP     STOSW
  2884.         MOV     AX,0BEE2H           ;LOOP
  2885.         STOSW
  2886.         MOV     AL,0C3H                 ;RET
  2887.         STOSB
  2888.         RET
  2889. ;
  2890.  
  2891. CLOCK_CALC_88   ENDP
  2892.  
  2893.  
  2894. ; *** TIMER START ROUTINE
  2895.  
  2896. TIMER_START PROC    NEAR            ;internal timing resolution = 838 ns
  2897.         CLI
  2898.         MOV     CS:TIMER_MICRO,0
  2899.         MOV     CS:TIMER_MILLI,0
  2900. ;--- INITIALIZE COUNTER 0 OF 8253 TIMER ----
  2901.         MOV     AL,00110100B            ;CNT 0,LSB then MSB, MODE 2, BINARY
  2902.         OUT     TIMER_MODE,AL
  2903.         JMP     SHORT $+2
  2904.         SUB     AX,AX
  2905.         OUT     TIMER0,AL
  2906.         JMP     SHORT $+2
  2907.         OUT     TIMER0,AL
  2908.         RET
  2909. TIMER_START ENDP
  2910.  
  2911. ; *** TIMER_STOP ROUTINE ***
  2912.  
  2913. TIMER_STOP  PROC    NEAR
  2914.         MOV     AL,00H
  2915.         OUT     TIMER_MODE,AL           ;LATCH COUNTER ( 16 bits )
  2916.         JMP     SHORT $+2
  2917.         IN      AL,TIMER0               ;READ LOWER 8 bits
  2918.         JMP     SHORT $+2
  2919.         MOV     DL,AL
  2920.         IN      AL,TIMER0               ;READ HIGHER 8 bits
  2921.         MOV     DH,AL               ;DX HAS 16 BIT TIMER COUNT
  2922.         STI
  2923. ;-- CALC THE TIME
  2924.         XOR     AX,AX
  2925.         SUB     AX,DX
  2926.         MUL     CS:TIMER_CONVERT
  2927.         DIV     CS:TEN_THOUSAND
  2928.         MOV     CS:TIMER_MICRO,AX
  2929.         MOV     AX,CS:TIMER_MICRO
  2930.         CMP     AX,1000
  2931.         JB      FLD_OK
  2932.         SUB     DX,DX
  2933.         DIV     CS:THOUSAND
  2934.         MOV     CS:TIMER_MILLI,AX
  2935.         MOV     CS:TIMER_MICRO,DX
  2936. FLD_OK:
  2937. DISP_END:
  2938.         RET
  2939. TIMER_STOP  ENDP
  2940.  
  2941. _LAST   ends
  2942.  
  2943.         end
  2944.  
  2945.